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/10/01 09:48:48 UTC

[01/12] tinkerpop git commit: Added a Gryo serializer for Bytecode. TINKERPOP-1464 [Forced Update!]

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1467-master c58866892 -> 9d860ca0c (forced update)


Added a Gryo serializer for Bytecode. TINKERPOP-1464


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 66d206a098f3c68d7bfb174c50d927f1181c18ff
Parents: b8530f7
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Sat Sep 24 14:03:30 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Sat Sep 24 14:03:30 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   2 +
 .../gremlin/process/traversal/Bytecode.java     |   2 -
 .../structure/io/gryo/EntrySerializer.java      |  43 -----
 .../structure/io/gryo/GryoClassResolver.java    |   3 +
 .../gremlin/structure/io/gryo/GryoMapper.java   |  35 +++-
 .../structure/io/gryo/GryoSerializers.java      | 178 +++++++++++++++++--
 .../structure/io/gryo/PairSerializer.java       |  45 -----
 .../structure/io/gryo/URISerializer.java        |  49 -----
 .../structure/io/gryo/UUIDSerializer.java       |  50 ------
 .../structure/io/gryo/UtilSerializers.java      | 140 +++++++++++++++
 10 files changed, 337 insertions(+), 210 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index a1b405f..a3e21a1 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -31,6 +31,8 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Fixed a bug in serialization of `Lambda` instances in GraphSON, which prevented their use in remote traversals.
 * Fixed a naming bug in Gremlin-Python where `P._and` and `P._or` should be `P.and_` and `P.or_`. (*breaking*)
 * `where()` predicate-based steps now support `by()`-modulation.
+* Added Gryo serialization for `Bytecode`.
+* Moved utility-based serializers to `UtilSerializers` for Gryo - these classes were private and hence this change is non-breaking.
 * `TraversalRing` returns a `null` if it does not contain traversals (previously `IdentityTraversal`).
 * Fixed a `JavaTranslator` bug where `Bytecode` instructions were being mutated during translation.
 * Added `Path` to Gremlin-Python with respective GraphSON 2.0 deserializer.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
index c200741..3737cef 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Bytecode.java
@@ -191,8 +191,6 @@ public final class Bytecode implements Cloneable, Serializable {
         public int hashCode() {
             return this.operator.hashCode() + Arrays.hashCode(this.arguments);
         }
-
-
     }
 
     public static class Binding<V> implements Serializable {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/EntrySerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/EntrySerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/EntrySerializer.java
deleted file mode 100644
index 00215e0..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/EntrySerializer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.structure.io.gryo;
-
-import org.apache.tinkerpop.shaded.kryo.Kryo;
-import org.apache.tinkerpop.shaded.kryo.Serializer;
-import org.apache.tinkerpop.shaded.kryo.io.Input;
-import org.apache.tinkerpop.shaded.kryo.io.Output;
-
-import java.util.AbstractMap;
-import java.util.Map;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-final class EntrySerializer extends Serializer<Map.Entry> {
-    @Override
-    public void write(final Kryo kryo, final Output output, final Map.Entry entry) {
-        kryo.writeClassAndObject(output, entry.getKey());
-        kryo.writeClassAndObject(output, entry.getValue());
-    }
-
-    @Override
-    public Map.Entry read(final Kryo kryo, final Input input, final Class<Map.Entry> entryClass) {
-        return new AbstractMap.SimpleEntry(kryo.readClassAndObject(input), kryo.readClassAndObject(input));
-    }
-}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoClassResolver.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoClassResolver.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoClassResolver.java
index 5d51d22..53f4382 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoClassResolver.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoClassResolver.java
@@ -33,6 +33,7 @@ import org.apache.tinkerpop.gremlin.structure.util.reference.ReferencePath;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceProperty;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.apache.tinkerpop.shaded.kryo.ClassResolver;
 import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.apache.tinkerpop.shaded.kryo.KryoException;
@@ -105,6 +106,8 @@ public class GryoClassResolver implements ClassResolver {
             type = Property.class;
         else if (!ReferencePath.class.isAssignableFrom(clazz) && !DetachedPath.class.isAssignableFrom(clazz) && Path.class.isAssignableFrom(clazz))
             type = Path.class;
+        else if (Lambda.class.isAssignableFrom(clazz))
+            type = Lambda.class;
         else
             type = clazz;
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java
index add254e..0a7d277 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoMapper.java
@@ -26,7 +26,12 @@ import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraver
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.Contains;
 import org.apache.tinkerpop.gremlin.process.traversal.Operator;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.Pop;
+import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
+import org.apache.tinkerpop.gremlin.process.traversal.Scope;
 import org.apache.tinkerpop.gremlin.process.traversal.step.filter.RangeGlobalStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.FoldStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.map.GroupCountStep;
@@ -47,10 +52,13 @@ import org.apache.tinkerpop.gremlin.process.traversal.traverser.LP_O_OB_S_SE_SL_
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.O_OB_S_SE_SL_Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversalMetrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ImmutableMetrics;
 import org.apache.tinkerpop.gremlin.process.traversal.util.MutableMetrics;
+import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalExplanation;
+import org.apache.tinkerpop.gremlin.structure.Column;
 import org.apache.tinkerpop.gremlin.structure.Direction;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Graph;
@@ -74,6 +82,8 @@ import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertex;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.star.StarGraph;
 import org.apache.tinkerpop.gremlin.structure.util.star.StarGraphSerializer;
+import org.apache.tinkerpop.gremlin.util.function.HashSetSupplier;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.apache.tinkerpop.shaded.kryo.ClassResolver;
 import org.apache.tinkerpop.shaded.kryo.Kryo;
 import org.apache.tinkerpop.shaded.kryo.KryoSerializable;
@@ -177,7 +187,7 @@ public final class GryoMapper implements Mapper<Kryo> {
     @Override
     public Kryo createMapper() {
         final Kryo kryo = new Kryo(classResolver.get(), new MapReferenceResolver(), new DefaultStreamFactory());
-        kryo.addDefaultSerializer(Map.Entry.class, new EntrySerializer());
+        kryo.addDefaultSerializer(Map.Entry.class, new UtilSerializers.EntrySerializer());
         kryo.setRegistrationRequired(registrationRequired);
         kryo.setReferences(referenceTracking);
         for (TypeRegistration tr : typeRegistrations)
@@ -224,6 +234,8 @@ public final class GryoMapper implements Mapper<Kryo> {
             put("junk", "dummy");
         }};
 
+        private static final Class ARRAYS_AS_LIST = Arrays.asList("dummy").getClass();
+
         private static final Class LINKED_HASH_MAP_ENTRY_CLASS = m.entrySet().iterator().next().getClass();
 
         /**
@@ -257,6 +269,7 @@ public final class GryoMapper implements Mapper<Kryo> {
             add(GryoTypeReg.of(String[].class, 32));
             add(GryoTypeReg.of(Object[].class, 33));
             add(GryoTypeReg.of(ArrayList.class, 10));
+            add(GryoTypeReg.of(ARRAYS_AS_LIST, 134, new UtilSerializers.ArraysAsListSerializer()));
             add(GryoTypeReg.of(BigInteger.class, 34));
             add(GryoTypeReg.of(BigDecimal.class, 35));
             add(GryoTypeReg.of(Calendar.class, 39));
@@ -294,8 +307,8 @@ public final class GryoMapper implements Mapper<Kryo> {
             add(GryoTypeReg.of(TimeZone.class, 42));
             add(GryoTypeReg.of(TreeMap.class, 45));
             add(GryoTypeReg.of(TreeSet.class, 50));
-            add(GryoTypeReg.of(UUID.class, 17, new UUIDSerializer()));
-            add(GryoTypeReg.of(URI.class, 72, new URISerializer()));
+            add(GryoTypeReg.of(UUID.class, 17, new UtilSerializers.UUIDSerializer()));
+            add(GryoTypeReg.of(URI.class, 72, new UtilSerializers.URISerializer()));
             add(GryoTypeReg.of(VertexTerminator.class, 13));
             add(GryoTypeReg.of(AbstractMap.SimpleEntry.class, 120));
             add(GryoTypeReg.of(AbstractMap.SimpleImmutableEntry.class, 121));
@@ -322,9 +335,21 @@ public final class GryoMapper implements Mapper<Kryo> {
             add(GryoTypeReg.of(O_OB_S_SE_SL_Traverser.class, 89));
             add(GryoTypeReg.of(LP_O_OB_S_SE_SL_Traverser.class, 90));
             add(GryoTypeReg.of(LP_O_OB_P_S_SE_SL_Traverser.class, 91));
-            add(GryoTypeReg.of(DefaultRemoteTraverser.class, 123, new GryoSerializers.DefaultRemoteTraverserSerializer()));  // ***LAST ID***
+            add(GryoTypeReg.of(DefaultRemoteTraverser.class, 123, new GryoSerializers.DefaultRemoteTraverserSerializer()));
 
             add(GryoTypeReg.of(Bytecode.class, 122, new GryoSerializers.BytecodeSerializer()));
+            add(GryoTypeReg.of(P.class, 124, new GryoSerializers.PSerializer()));
+            add(GryoTypeReg.of(Lambda.class, 125, new GryoSerializers.LambdaSerializer()));
+            add(GryoTypeReg.of(Bytecode.Binding.class, 126, new GryoSerializers.BindingSerializer()));
+            add(GryoTypeReg.of(Order.class, 127));
+            add(GryoTypeReg.of(Scope.class, 128));
+            add(GryoTypeReg.of(AndP.class, 129, new GryoSerializers.AndPSerializer()));
+            add(GryoTypeReg.of(OrP.class, 130, new GryoSerializers.OrPSerializer()));
+            add(GryoTypeReg.of(VertexProperty.Cardinality.class, 131));
+            add(GryoTypeReg.of(Column.class, 132));
+            add(GryoTypeReg.of(Pop.class, 133));
+            add(GryoTypeReg.of(SackFunctions.Barrier.class, 135));
+            add(GryoTypeReg.of(HashSetSupplier.class, 136, new UtilSerializers.HashSetSupplierSerializer())); // ***LAST ID***
 
             add(GryoTypeReg.of(TraverserSet.class, 58));
             add(GryoTypeReg.of(Tree.class, 61));
@@ -336,7 +361,7 @@ public final class GryoMapper implements Mapper<Kryo> {
             add(GryoTypeReg.of(MapMemory.class, 73));
             add(GryoTypeReg.of(MapReduce.NullObject.class, 74));
             add(GryoTypeReg.of(AtomicLong.class, 79));
-            add(GryoTypeReg.of(Pair.class, 88, new PairSerializer()));
+            add(GryoTypeReg.of(Pair.class, 88, new UtilSerializers.PairSerializer()));
             add(GryoTypeReg.of(TraversalExplanation.class, 106, new JavaSerializer()));
 
             add(GryoTypeReg.of(Duration.class, 93, new JavaTimeSerializers.DurationSerializer()));

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializers.java
index 945af87..dbe85ca 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializers.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializers.java
@@ -20,14 +20,16 @@ package org.apache.tinkerpop.gremlin.structure.io.gryo;
 
 import org.apache.tinkerpop.gremlin.process.remote.traversal.DefaultRemoteTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Path;
+import org.apache.tinkerpop.gremlin.process.traversal.util.AndP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
+import org.apache.tinkerpop.gremlin.process.traversal.util.OrP;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.InputShim;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShim;
 import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.OutputShim;
@@ -38,6 +40,12 @@ import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedPath;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
+import org.apache.tinkerpop.gremlin.util.function.Lambda;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * Class used to serialize graph-based objects such as vertices, edges, properties, and paths. These objects are
@@ -126,30 +134,168 @@ public final class GryoSerializers {
     }
 
     public final static class BytecodeSerializer implements SerializerShim<Bytecode> {
-        private static final GraphSONMapper mapper = GraphSONMapper.build()
-                .version(GraphSONVersion.V2_0)
-                .addCustomModule(GraphSONXModuleV2d0.build().create(false))
-                .create();
-
         @Override
         public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Bytecode bytecode) {
-            try {
-                output.writeString(mapper.createMapper().writeValueAsString(bytecode));
-            } catch (Exception ex) {
-                throw new RuntimeException(ex);
-            }
+            final List<Bytecode.Instruction> sourceInstructions = IteratorUtils.list(
+                    IteratorUtils.filter(bytecode.getSourceInstructions().iterator(),
+                            i -> !i.getOperator().equals("withStrategies") && !i.getOperator().equals("withComputer")));
+            writeInstructions(kryo, output, sourceInstructions);
+            final List<Bytecode.Instruction> stepInstructions = IteratorUtils.list(bytecode.getStepInstructions().iterator());
+            writeInstructions(kryo, output, stepInstructions);
         }
 
         @Override
         public <I extends InputShim> Bytecode read(final KryoShim<I, ?> kryo, final I input, final Class<Bytecode> clazz) {
+            final Bytecode bytecode = new Bytecode();
+            final int sourceInstructionCount = input.readInt();
+            for (int ix = 0; ix < sourceInstructionCount; ix++) {
+                final String operator = input.readString();
+                final Object[] args = kryo.readObject(input, Object[].class);
+                bytecode.addSource(operator, args);
+            }
+
+            final int stepInstructionCount = input.readInt();
+            for (int ix = 0; ix < stepInstructionCount; ix++) {
+                final String operator = input.readString();
+                final Object[] args = kryo.readObject(input, Object[].class);
+                bytecode.addStep(operator, args);
+            }
+
+            return bytecode;
+        }
+
+        private static <O extends OutputShim> void writeInstructions(final KryoShim<?, O> kryo, final O output,
+                                                                     final List<Bytecode.Instruction> instructions) {
+            output.writeInt(instructions.size());
+            for (Bytecode.Instruction inst : instructions) {
+                output.writeString(inst.getOperator());
+                kryo.writeObject(output, inst.getArguments());
+            }
+        }
+    }
+
+    public final static class AndPSerializer implements SerializerShim<AndP> {
+
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final AndP p) {
+            final List predicates = new ArrayList(p.getPredicates());
+            kryo.writeObject(output, predicates);
+        }
+
+        @Override
+        public <I extends InputShim> AndP read(final KryoShim<I, ?> kryo, final I input, final Class<AndP> clazz) {
+            final List<P> predicates = kryo.readObject(input, ArrayList.class);
+            return new AndP(predicates);
+        }
+    }
+
+    public final static class OrPSerializer implements SerializerShim<OrP> {
+
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final OrP p) {
+            final List predicates = new ArrayList(p.getPredicates());
+            kryo.writeObject(output, predicates);
+        }
+
+        @Override
+        public <I extends InputShim> OrP read(final KryoShim<I, ?> kryo, final I input, final Class<OrP> clazz) {
+            final List<P> predicates = kryo.readObject(input, ArrayList.class);
+            return new OrP(predicates);
+        }
+    }
+
+    public final static class PSerializer implements SerializerShim<P> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final P p) {
+            output.writeString(p.getBiPredicate().toString());
+            if (p.getValue() instanceof Collection) {
+                output.writeByte((byte) 0);
+                final Collection coll = (Collection) p.getValue();
+                output.writeInt(coll.size());
+                coll.forEach(v -> kryo.writeClassAndObject(output, v));
+            } else {
+                output.writeByte((byte) 1);
+                kryo.writeClassAndObject(output, p.getValue());
+            }
+        }
+
+        @Override
+        public <I extends InputShim> P read(final KryoShim<I, ?> kryo, final I input, final Class<P> clazz) {
+            final String predicate = input.readString();
+            final boolean isCollection = input.readByte() == (byte) 0;
+            final Object value;
+            if (isCollection) {
+                value = new ArrayList();
+                final int size = input.readInt();
+                for (int ix = 0; ix < size; ix++) {
+                    ((List) value).add(kryo.readClassAndObject(input));
+                }
+            } else {
+                value = kryo.readClassAndObject(input);
+            }
+
             try {
-                return mapper.createMapper().readValue(input.readString(), Bytecode.class);
-            } catch (Exception ex) {
-                throw new RuntimeException(ex);
+                if (value instanceof Collection) {
+                    if (predicate.equals("between"))
+                        return P.between(((List) value).get(0), ((List) value).get(1));
+                    else if (predicate.equals("inside"))
+                        return P.between(((List) value).get(0), ((List) value).get(1));
+                    else if (predicate.equals("outside"))
+                        return P.outside(((List) value).get(0), ((List) value).get(1));
+                    else if (predicate.equals("within"))
+                        return P.within((Collection) value);
+                    else if (predicate.equals("without"))
+                        return P.without((Collection) value);
+                    else
+                        return (P) P.class.getMethod(predicate, Collection.class).invoke(null, (Collection) value);
+                } else
+                    return (P) P.class.getMethod(predicate, Object.class).invoke(null, value);
+            } catch (final Exception e) {
+                throw new IllegalStateException(e.getMessage(), e);
             }
         }
     }
 
+    public final static class LambdaSerializer implements SerializerShim<Lambda> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Lambda lambda) {
+            output.writeString(lambda.getLambdaScript());
+            output.writeString(lambda.getLambdaLanguage());
+            output.writeInt(lambda.getLambdaArguments());
+        }
+
+        @Override
+        public <I extends InputShim> Lambda read(final KryoShim<I, ?> kryo, final I input, final Class<Lambda> clazz) {
+            final String script = input.readString();
+            final String language = input.readString();
+            final int arguments = input.readInt();
+            //
+            if (-1 == arguments || arguments > 2)
+                return new Lambda.UnknownArgLambda(script, language, arguments);
+            else if (0 == arguments)
+                return new Lambda.ZeroArgLambda<>(script, language);
+            else if (1 == arguments)
+                return new Lambda.OneArgLambda<>(script, language);
+            else
+                return new Lambda.TwoArgLambda<>(script, language);
+        }
+    }
+
+    public final static class BindingSerializer implements SerializerShim<Bytecode.Binding> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Bytecode.Binding binding) {
+            output.writeString(binding.variable());
+            kryo.writeClassAndObject(output, binding.value());
+        }
+
+        @Override
+        public <I extends InputShim> Bytecode.Binding read(final KryoShim<I, ?> kryo, final I input, final Class<Bytecode.Binding> clazz) {
+            final String var = input.readString();
+            final Object val = kryo.readClassAndObject(input);
+            return new Bytecode.Binding(var, val);
+        }
+    }
+
     public final static class DefaultRemoteTraverserSerializer implements SerializerShim<DefaultRemoteTraverser> {
         @Override
         public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final DefaultRemoteTraverser remoteTraverser) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/PairSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/PairSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/PairSerializer.java
deleted file mode 100644
index 1465b24..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/PairSerializer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.structure.io.gryo;
-
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.InputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.OutputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.SerializerShim;
-import org.apache.tinkerpop.shaded.kryo.Kryo;
-import org.apache.tinkerpop.shaded.kryo.Serializer;
-import org.apache.tinkerpop.shaded.kryo.io.Input;
-import org.apache.tinkerpop.shaded.kryo.io.Output;
-import org.javatuples.Pair;
-
-/**
- * @author Daniel Kuppitz (http://gremlin.guru)
- */
-final class PairSerializer implements SerializerShim<Pair> {
-    @Override
-    public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Pair pair) {
-        kryo.writeClassAndObject(output, pair.getValue0());
-        kryo.writeClassAndObject(output, pair.getValue1());
-    }
-
-    @Override
-    public <I extends InputShim> Pair read(final KryoShim<I, ?> kryo, final I input, final Class<Pair> pairClass) {
-        return Pair.with(kryo.readClassAndObject(input), kryo.readClassAndObject(input));
-    }
-}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/URISerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/URISerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/URISerializer.java
deleted file mode 100644
index a65bcea..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/URISerializer.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.structure.io.gryo;
-
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.InputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.OutputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.SerializerShim;
-
-import java.net.URI;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-final class URISerializer implements SerializerShim<URI> {
-
-    public URISerializer() { }
-
-    @Override
-    public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final URI uri) {
-        output.writeString(uri.toString());
-    }
-
-    @Override
-    public <I extends InputShim> URI read(final KryoShim<I, ?> kryo, final I input, final Class<URI> uriClass) {
-        return URI.create(input.readString());
-    }
-
-    @Override
-    public boolean isImmutable() {
-        return true;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UUIDSerializer.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UUIDSerializer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UUIDSerializer.java
deleted file mode 100644
index d1d59d3..0000000
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UUIDSerializer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.tinkerpop.gremlin.structure.io.gryo;
-
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.InputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.OutputShim;
-import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.SerializerShim;
-
-import java.util.UUID;
-
-/**
- * @author Stephen Mallette (http://stephen.genoprime.com)
- */
-final class UUIDSerializer implements SerializerShim<UUID> {
-
-    public UUIDSerializer() { }
-
-    @Override
-    public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final UUID uuid) {
-        output.writeLong(uuid.getMostSignificantBits());
-        output.writeLong(uuid.getLeastSignificantBits());
-    }
-
-    @Override
-    public <I extends InputShim> UUID read(final KryoShim<I, ?> kryo, final I input, final Class<UUID> uuidClass) {
-        return new UUID(input.readLong(), input.readLong());
-    }
-
-    @Override
-    public boolean isImmutable() {
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/66d206a0/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UtilSerializers.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UtilSerializers.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UtilSerializers.java
new file mode 100644
index 0000000..6f0a632
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/UtilSerializers.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.structure.io.gryo;
+
+import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.InputShim;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.KryoShim;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.OutputShim;
+import org.apache.tinkerpop.gremlin.structure.io.gryo.kryoshim.SerializerShim;
+import org.apache.tinkerpop.gremlin.util.function.HashSetSupplier;
+import org.apache.tinkerpop.shaded.kryo.Kryo;
+import org.apache.tinkerpop.shaded.kryo.Serializer;
+import org.apache.tinkerpop.shaded.kryo.io.Input;
+import org.apache.tinkerpop.shaded.kryo.io.Output;
+import org.javatuples.Pair;
+
+import java.net.URI;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @author Daniel Kuppitz (http://gremlin.guru)
+ */
+final class UtilSerializers {
+
+    private UtilSerializers() {}
+
+    /**
+     * Serializer for {@code List} instances produced by {@code Arrays.asList()}.
+     */
+    public final static class ArraysAsListSerializer implements SerializerShim<List> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final List list) {
+            final List l = new ArrayList(list);
+            kryo.writeObject(output, l);
+        }
+
+        @Override
+        public <I extends InputShim> List read(final KryoShim<I, ?> kryo, final I input, final Class<List> clazz) {
+            return kryo.readObject(input, ArrayList.class);
+        }
+    }
+
+    public final static class HashSetSupplierSerializer implements SerializerShim<HashSetSupplier> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final HashSetSupplier hashSetSupplier) {
+        }
+
+        @Override
+        public <I extends InputShim> HashSetSupplier read(final KryoShim<I, ?> kryo, final I input, final Class<HashSetSupplier> clazz) {
+            return HashSetSupplier.instance();
+        }
+    }
+
+    static final class UUIDSerializer implements SerializerShim<UUID> {
+
+        public UUIDSerializer() { }
+
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final UUID uuid) {
+            output.writeLong(uuid.getMostSignificantBits());
+            output.writeLong(uuid.getLeastSignificantBits());
+        }
+
+        @Override
+        public <I extends InputShim> UUID read(final KryoShim<I, ?> kryo, final I input, final Class<UUID> uuidClass) {
+            return new UUID(input.readLong(), input.readLong());
+        }
+
+        @Override
+        public boolean isImmutable() {
+            return true;
+        }
+    }
+
+    static final class URISerializer implements SerializerShim<URI> {
+
+        public URISerializer() { }
+
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final URI uri) {
+            output.writeString(uri.toString());
+        }
+
+        @Override
+        public <I extends InputShim> URI read(final KryoShim<I, ?> kryo, final I input, final Class<URI> uriClass) {
+            return URI.create(input.readString());
+        }
+
+        @Override
+        public boolean isImmutable() {
+            return true;
+        }
+    }
+
+    static final class PairSerializer implements SerializerShim<Pair> {
+        @Override
+        public <O extends OutputShim> void write(final KryoShim<?, O> kryo, final O output, final Pair pair) {
+            kryo.writeClassAndObject(output, pair.getValue0());
+            kryo.writeClassAndObject(output, pair.getValue1());
+        }
+
+        @Override
+        public <I extends InputShim> Pair read(final KryoShim<I, ?> kryo, final I input, final Class<Pair> pairClass) {
+            return Pair.with(kryo.readClassAndObject(input), kryo.readClassAndObject(input));
+        }
+    }
+
+    static final class EntrySerializer extends Serializer<Map.Entry> {
+        @Override
+        public void write(final Kryo kryo, final Output output, final Map.Entry entry) {
+            kryo.writeClassAndObject(output, entry.getKey());
+            kryo.writeClassAndObject(output, entry.getValue());
+        }
+
+        @Override
+        public Map.Entry read(final Kryo kryo, final Input input, final Class<Map.Entry> entryClass) {
+            return new AbstractMap.SimpleEntry(kryo.readClassAndObject(input), kryo.readClassAndObject(input));
+        }
+    }
+}


[10/12] tinkerpop git commit: Merge branch 'tp31'

Posted by sp...@apache.org.
Merge branch 'tp31'


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: ee813e90230145297aa6b5c30cbbb4a4fe7857cd
Parents: f2b027b 85ec40b
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Sep 30 13:05:48 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 13:05:48 2016 -0400

----------------------------------------------------------------------
 docs/src/dev/developer/release.asciidoc | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ee813e90/docs/src/dev/developer/release.asciidoc
----------------------------------------------------------------------


[11/12] tinkerpop git commit: Added simple validations to Cluster instance creations CTR

Posted by sp...@apache.org.
Added simple validations to Cluster instance creations CTR


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 233a6ba460f618a5c684f0bc2533175f90948d0e
Parents: ee813e9
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Sep 30 14:52:43 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 14:52:43 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../tinkerpop/gremlin/driver/Cluster.java       | 55 +++++++++++-
 .../gremlin/driver/ClusterBuilderTest.java      | 88 ++++++++++++++++++++
 3 files changed, 142 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/233a6ba4/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 9b3be83..ade43cd 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -59,6 +59,7 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Renamed the `empty.result.indicator` preference to `result.indicator.null` in Gremlin Console
 * If `result.indicator.null` is set to an empty string, then no "result line" is printed in Gremlin Console.
 * Deprecated `reconnectInitialDelay` on the Java driver.
+* Added some validations to `Cluster` instance building.
 * Produced better errors in `readGraph` of `GryoReader` and `GraphSONReader` if a `Vertex` cannot be found in the cache on edge loading.
 * VertexPrograms can now declare traverser requirements, e.g. to have access to the path when used with `.program()`.
 * New build options for `gremlin-python` where `-DglvPython` is no longer required.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/233a6ba4/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 f420de0..b9a3cee 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
@@ -510,7 +510,6 @@ public final class Cluster {
          * Size of the pool for handling request/response operations.  Defaults to the number of available processors.
          */
         public Builder nioPoolSize(final int nioPoolSize) {
-            if (nioPoolSize < 1) throw new IllegalArgumentException("The workerPoolSize must be greater than zero");
             this.nioPoolSize = nioPoolSize;
             return this;
         }
@@ -520,7 +519,6 @@ public final class Cluster {
          * by 2
          */
         public Builder workerPoolSize(final int workerPoolSize) {
-            if (workerPoolSize < 1) throw new IllegalArgumentException("The workerPoolSize must be greater than zero");
             this.workerPoolSize = workerPoolSize;
             return this;
         }
@@ -872,6 +870,8 @@ public final class Cluster {
         private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
 
         private Manager(final Builder builder) {
+            validateBuilder(builder);
+
             this.loadBalancingStrategy = builder.loadBalancingStrategy;
             this.authProps = builder.authProps;
             this.contactPoints = builder.getContactPoints();
@@ -909,6 +909,57 @@ public final class Cluster {
                     new BasicThreadFactory.Builder().namingPattern("gremlin-driver-worker-%d").build());
         }
 
+        private void validateBuilder(final Builder builder) {
+            if (builder.minInProcessPerConnection < 0)
+                throw new IllegalArgumentException("minInProcessPerConnection must be greater than or equal to zero");
+
+            if (builder.maxInProcessPerConnection < 1)
+                throw new IllegalArgumentException("maxInProcessPerConnection must be greater than zero");
+
+            if (builder.minInProcessPerConnection > builder.maxInProcessPerConnection)
+                throw new IllegalArgumentException("maxInProcessPerConnection cannot be less than minInProcessPerConnection");
+
+            if (builder.minSimultaneousUsagePerConnection < 0)
+                throw new IllegalArgumentException("minSimultaneousUsagePerConnection must be greater than or equal to zero");
+
+            if (builder.maxSimultaneousUsagePerConnection < 1)
+                throw new IllegalArgumentException("maxSimultaneousUsagePerConnection must be greater than zero");
+
+            if (builder.minSimultaneousUsagePerConnection > builder.maxSimultaneousUsagePerConnection)
+                throw new IllegalArgumentException("maxSimultaneousUsagePerConnection cannot be less than minSimultaneousUsagePerConnection");
+
+            if (builder.minConnectionPoolSize < 0)
+                throw new IllegalArgumentException("minConnectionPoolSize must be greater than or equal to zero");
+
+            if (builder.maxConnectionPoolSize < 1)
+                throw new IllegalArgumentException("maxConnectionPoolSize must be greater than zero");
+
+            if (builder.minConnectionPoolSize > builder.maxConnectionPoolSize)
+                throw new IllegalArgumentException("maxConnectionPoolSize cannot be less than minConnectionPoolSize");
+
+            if (builder.maxWaitForConnection < 1)
+                throw new IllegalArgumentException("maxWaitForConnection must be greater than zero");
+
+            if (builder.maxWaitForSessionClose < 1)
+                throw new IllegalArgumentException("maxWaitForSessionClose must be greater than zero");
+
+            if (builder.maxContentLength < 1)
+                throw new IllegalArgumentException("maxContentLength must be greater than zero");
+
+            if (builder.reconnectInterval < 1)
+                throw new IllegalArgumentException("reconnectInterval must be greater than zero");
+
+            if (builder.resultIterationBatchSize < 1)
+                throw new IllegalArgumentException("resultIterationBatchSize must be greater than zero");
+
+            if (builder.nioPoolSize < 1)
+                throw new IllegalArgumentException("nioPoolSize must be greater than zero");
+
+            if (builder.workerPoolSize < 1)
+                throw new IllegalArgumentException("workerPoolSize must be greater than zero");
+
+        }
+
         synchronized void init() {
             if (initialized)
                 return;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/233a6ba4/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
new file mode 100644
index 0000000..cb5c469
--- /dev/null
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ClusterBuilderTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.driver;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+@RunWith(Parameterized.class)
+public class ClusterBuilderTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Iterable<Object[]> data() {
+        return Arrays.asList(new Object[][]{
+                {"maxInProcessPerConnection0", Cluster.build().maxInProcessPerConnection(0), "maxInProcessPerConnection must be greater than zero"},
+                {"maxInProcessPerConnectionNeg1", Cluster.build().maxInProcessPerConnection(-1), "maxInProcessPerConnection must be greater than zero"},
+                {"minInProcessPerConnectionNeg1", Cluster.build().minInProcessPerConnection(-1), "minInProcessPerConnection must be greater than or equal to zero"},
+                {"minInProcessPerConnectionLtMax", Cluster.build().minInProcessPerConnection(100).maxInProcessPerConnection(99), "maxInProcessPerConnection cannot be less than minInProcessPerConnection"},
+                {"maxSimultaneousUsagePerConnection0", Cluster.build().maxSimultaneousUsagePerConnection(0), "maxSimultaneousUsagePerConnection must be greater than zero"},
+                {"maxSimultaneousUsagePerConnectionNeg1", Cluster.build().maxSimultaneousUsagePerConnection(-1), "maxSimultaneousUsagePerConnection must be greater than zero"},
+                {"minSimultaneousUsagePerConnectionNeg1", Cluster.build().minSimultaneousUsagePerConnection(-1), "minSimultaneousUsagePerConnection must be greater than or equal to zero"},
+                {"minSimultaneousUsagePerConnectionLtMax", Cluster.build().minSimultaneousUsagePerConnection(100).maxSimultaneousUsagePerConnection(99), "maxSimultaneousUsagePerConnection cannot be less than minSimultaneousUsagePerConnection"},
+                {"maxConnectionPoolSize0", Cluster.build().maxConnectionPoolSize(0), "maxConnectionPoolSize must be greater than zero"},
+                {"maxConnectionPoolSizeNeg1", Cluster.build().maxConnectionPoolSize(-1), "maxConnectionPoolSize must be greater than zero"},
+                {"minConnectionPoolSizeNeg1", Cluster.build().minConnectionPoolSize(-1), "minConnectionPoolSize must be greater than or equal to zero"},
+                {"minConnectionPoolSizeLteMax", Cluster.build().minConnectionPoolSize(100).maxConnectionPoolSize(99), "maxConnectionPoolSize cannot be less than minConnectionPoolSize"},
+                {"minConnectionPoolSizeLteMax", Cluster.build().minConnectionPoolSize(100).maxConnectionPoolSize(99), "maxConnectionPoolSize cannot be less than minConnectionPoolSize"},
+                {"maxConnectionPoolSize0", Cluster.build().maxWaitForConnection(0), "maxWaitForConnection must be greater than zero"},
+                {"maxWaitForSessionClose0", Cluster.build().maxWaitForSessionClose(0), "maxWaitForSessionClose must be greater than zero"},
+                {"maxWaitForSessionCloseNeg1", Cluster.build().maxWaitForSessionClose(-1), "maxWaitForSessionClose must be greater than zero"},
+                {"maxContentLength0", Cluster.build().maxContentLength(0), "maxContentLength must be greater than zero"},
+                {"maxContentLengthNeg1", Cluster.build().maxContentLength(-1), "maxContentLength must be greater than zero"},
+                {"reconnectInterval0", Cluster.build().reconnectInterval(0), "reconnectInterval must be greater than zero"},
+                {"reconnectIntervalNeg1", Cluster.build().reconnectInterval(-1), "reconnectInterval must be greater than zero"},
+                {"resultIterationBatchSize0", Cluster.build().resultIterationBatchSize(0), "resultIterationBatchSize must be greater than zero"},
+                {"resultIterationBatchSizeNeg1", Cluster.build().resultIterationBatchSize(-1), "resultIterationBatchSize must be greater than zero"},
+                {"nioPoolSize0", Cluster.build().nioPoolSize(0), "nioPoolSize must be greater than zero"},
+                {"nioPoolSizeNeg1", Cluster.build().nioPoolSize(-1), "nioPoolSize must be greater than zero"},
+                {"workerPoolSize0", Cluster.build().workerPoolSize(0), "workerPoolSize must be greater than zero"},
+                {"workerPoolSizeNeg1", Cluster.build().workerPoolSize(-1), "workerPoolSize must be greater than zero"}});
+    }
+
+    @Parameterized.Parameter(value = 0)
+    public String name;
+
+    @Parameterized.Parameter(value = 1)
+    public Cluster.Builder builder;
+
+    @Parameterized.Parameter(value = 2)
+    public String expectedErrorMessage;
+
+    @Test
+    public void shouldNotConstructAnInvalidConnection() {
+        try {
+            builder.create();
+            fail("Should not have created cluster instance");
+        } catch (Exception ex) {
+            assertThat(ex, instanceOf(IllegalArgumentException.class));
+            assertEquals(expectedErrorMessage, ex.getMessage());
+        }
+    }
+}


[07/12] tinkerpop git commit: Improved errors produced by GraphSON/GryoReader.readGraph()

Posted by sp...@apache.org.
Improved errors produced by GraphSON/GryoReader.readGraph()

in cases where the edge is being loaded and the vertex cannot be found in the cache. No such change was needed for GraphML as it has a slightly different loading model. CTR


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 8d0d2f161dea16a569c27d48f7cc34c0d94a4ab9
Parents: 4fc05e8
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Sep 30 12:16:44 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 12:16:44 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                               | 1 +
 .../tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java  | 4 ++++
 .../apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java   | 4 ++++
 3 files changed, 9 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8d0d2f16/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index cfa5a07..9b3be83 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -59,6 +59,7 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Renamed the `empty.result.indicator` preference to `result.indicator.null` in Gremlin Console
 * If `result.indicator.null` is set to an empty string, then no "result line" is printed in Gremlin Console.
 * Deprecated `reconnectInitialDelay` on the Java driver.
+* Produced better errors in `readGraph` of `GryoReader` and `GraphSONReader` if a `Vertex` cannot be found in the cache on edge loading.
 * VertexPrograms can now declare traverser requirements, e.g. to have access to the path when used with `.program()`.
 * New build options for `gremlin-python` where `-DglvPython` is no longer required.
 * Added missing `InetAddress` to GraphSON extension module.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8d0d2f16/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
index 667aa86..a1ccc5e 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONReader.java
@@ -114,6 +114,10 @@ public final class GraphSONReader implements GraphReader {
             // StarAdjacentVertex whose equality should match StarVertex.
             final Vertex cachedOutV = cache.get(e.outVertex());
             final Vertex cachedInV = cache.get(e.inVertex());
+
+            if (null == cachedOutV) throw new IllegalStateException(String.format("Could not find outV with id [%s] to create edge with id [%s]", e.outVertex().id(), e.id()));
+            if (null == cachedInV) throw new IllegalStateException(String.format("Could not find inV with id [%s] to create edge with id [%s]", e.inVertex().id(), e.id()));
+
             final Edge newEdge = edgeFeatures.willAllowId(e.id()) ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
             e.properties().forEachRemaining(p -> newEdge.property(p.key(), p.value()));
             if (supportsTx && counter.incrementAndGet() % batchSize == 0)

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8d0d2f16/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
index c34101b..d9e9d7b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoReader.java
@@ -103,6 +103,10 @@ public final class GryoReader implements GraphReader {
             // StarAdjacentVertex whose equality should match StarVertex.
             final Vertex cachedOutV = cache.get(e.outVertex());
             final Vertex cachedInV = cache.get(e.inVertex());
+
+            if (null == cachedOutV) throw new IllegalStateException(String.format("Could not find outV with id [%s] to create edge with id [%s]", e.outVertex().id(), e.id()));
+            if (null == cachedInV) throw new IllegalStateException(String.format("Could not find inV with id [%s] to create edge with id [%s]", e.inVertex().id(), e.id()));
+
             final Edge newEdge = edgeFeatures.willAllowId(e.id()) ? cachedOutV.addEdge(e.label(), cachedInV, T.id, e.id()) : cachedOutV.addEdge(e.label(), cachedInV);
             e.properties().forEachRemaining(p -> newEdge.property(p.key(), p.value()));
             if (supportsTx && counter.incrementAndGet() % batchSize == 0)


[02/12] tinkerpop git commit: TraversalSource and Traversal implement AutoCloseable.

Posted by sp...@apache.org.
TraversalSource and Traversal implement AutoCloseable.

This allowed for TraversalSource instances created using withRemote() to close out open RemoteConnection instances. It also sets up for side-effects created by a "remote" Traversal to be cleared from cache on the server. That work is not done yet and is reserved for a different ticket.


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: b732718635fe22ba13e546d4623eb4d2c1150839
Parents: 7a4a836
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Sat Sep 24 22:18:56 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed Sep 28 13:37:36 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../src/reference/gremlin-applications.asciidoc | 10 +++-
 .../upgrade/release-3.2.x-incubating.asciidoc   | 25 +++++++++
 .../traversal/RemoteTraversalSideEffects.java   |  6 ++-
 .../gremlin/process/traversal/Traversal.java    |  7 ++-
 .../process/traversal/TraversalSource.java      | 15 +++---
 .../dsl/graph/GraphTraversalSource.java         | 24 +++++++--
 .../dsl/graph/GraphTraversalSourceTest.java     | 53 ++++++++++++++++++++
 .../driver/remote/DriverRemoteTraversal.java    | 13 +++++
 .../DriverRemoteTraversalSideEffects.java       |  7 +++
 10 files changed, 147 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 47d4bbf..dfb54fc 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -52,6 +52,7 @@ TinkerPop 3.2.3 (Release Date: NOT OFFICIALLY RELEASED YET)
 * Deprecated `Graph.Exceptions.elementNotFoundException()` as it was not used in the code base outside of the test suite.
 * Fixed a `JavaTranslator` bug where `Bytecode` instructions were being mutated during translation.
 * Added `Path` to Gremlin-Python with respective GraphSON 2.0 deserializer.
+* `Traversal` and `TraversalSource` now implement `AutoCloseable`.
 * Added "keep-alive" functionality to the Java driver, which will send a heartbeat to the server when normal request activity on a connection stops for a period of time.
 * Renamed the `empty.result.indicator` preference to `result.indicator.null` in Gremlin Console
 * If `result.indicator.null` is set to an empty string, then no "result line" is printed in Gremlin Console.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/docs/src/reference/gremlin-applications.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index 2f3fb1f..c452a0f 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -907,8 +907,13 @@ the `TraversalSource` be generated with `EmptyGraph` as follows:
 graph = EmptyGraph.instance()
 g = graph.traversal().withRemote('conf/remote-graph.properties')
 g.V().valueMap(true)
+g.close()
 ----
 
+Note the call to `close()` above. The call to `withRemote()` internally instantiates a `Client` instance that can only
+be released by "closing" the `GraphTraversalSource`. It is important to take that step to release resources created
+in that step.
+
 If working with multiple remote `TraversalSource` instances it is more efficient to construct a `Cluster` object and
 then re-use it.
 
@@ -918,11 +923,14 @@ cluster = Cluster.open('conf/remote-objects.yaml')
 graph = EmptyGraph.instance()
 g = graph.traversal().withRemote(DriverRemoteConnection.using(cluster, "g"))
 g.V().valueMap(true)
+g.close()
 cluster.close()
 ----
 
 If the `Cluster` instance is supplied externally, as is shown above, then it is not closed implicitly by the close of
-the `RemoteGraph`.  In this case, the `Cluster` must be closed explicitly.
+"g".  Closing "g" will only close the `Client` instance associated with that `TraversalSource`. In this case, the
+`Cluster` must also be closed explicitly. Closing "g" and the "cluster" aren't actually both necessary - the close of
+a `Cluster` will close all `Client` instance spawned by the `Cluster`.
 
 IMPORTANT: `RemoteGraph` uses the `TraversalOpProcessor` in Gremlin Server which requires a cache to enable the
 retrieval of side-effects (if the `Traversal` produces any). That cache can be configured (e.g. controlling eviction

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
index a6be1c6..0615099 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -118,6 +118,31 @@ gremlin> g.V().hasLabel("software").count()
 TinkerPop 3.2.3 fixes this misbehavior and all `has()` method overloads behave like before, except that they no longer
 support no arguments.
 
+TraversalSource.close()
+^^^^^^^^^^^^^^^^^^^^^^^
+
+`TraversalSource` now implements `AutoCloseable`, which means that the `close()` method is now available. This new
+method is important in cases where `withRemote()` is used, as `withRemote()` can open "expensive" resources that need
+to be released.
+
+In the case of TinkerPop's `DriverRemoteConnection`, `close()` will destroy the `Client` instance that is created
+internally by `withRemote()` as shown below:
+
+[source,text]
+----
+gremlin> graph = EmptyGraph.instance()
+==>emptygraph[empty]
+gremlin> g = graph.traversal().withRemote('conf/remote-graph.properties')
+==>graphtraversalsource[emptygraph[empty], standard]
+gremlin> g.close()
+gremlin>
+----
+
+Note that the `withRemote()` method will call `close()` on a `RemoteConnection` passed directly to it as well, so
+there is no need to do that manually.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-790[TINKERPOP-790]
+
 Upgrading for Providers
 ~~~~~~~~~~~~~~~~~~~~~~~
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
index e41a42d..97fb36d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/remote/traversal/RemoteTraversalSideEffects.java
@@ -23,5 +23,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.TraversalSideEffects;
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public interface RemoteTraversalSideEffects extends TraversalSideEffects {
+public interface RemoteTraversalSideEffects extends TraversalSideEffects, AutoCloseable {
+    @Override
+    public default void close() throws Exception {
+        //  do nothing
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
index eec9d3f..edc18e0 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Traversal.java
@@ -57,7 +57,7 @@ import java.util.stream.StreamSupport;
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable {
+public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable, AutoCloseable {
 
     public static class Symbols {
         private Symbols() {
@@ -231,6 +231,11 @@ public interface Traversal<S, E> extends Iterator<E>, Serializable, Cloneable {
         }
     }
 
+    @Override
+    public default void close() throws Exception {
+        // do nothing by default
+    }
+
     /**
      * A collection of {@link Exception} types associated with Traversal execution.
      */

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
index 7428d56..0d690e9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
@@ -53,7 +53,7 @@ import java.util.function.UnaryOperator;
  *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public interface TraversalSource extends Cloneable {
+public interface TraversalSource extends Cloneable, AutoCloseable {
 
     public static final String GREMLIN_REMOTE = "gremlin.remote.";
     public static final String GREMLIN_REMOTE_CONNECTION_CLASS = GREMLIN_REMOTE + "remoteConnectionClass";
@@ -427,14 +427,12 @@ public interface TraversalSource extends Cloneable {
 
     /**
      * Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
+     * Implementations should track {@link RemoteConnection} instances that are created and call
+     * {@link RemoteConnection#close()} on them when the {@code TraversalSource} itself is closed.
      *
      * @param connection the {@link RemoteConnection} instance to use to submit the {@link Traversal}.
      */
-    public default TraversalSource withRemote(final RemoteConnection connection) {
-        final TraversalSource clone = this.clone();
-        clone.getStrategies().addStrategies(new RemoteStrategy(connection));
-        return clone;
-    }
+    public TraversalSource withRemote(final RemoteConnection connection);
 
     public default Optional<Class> getAnonymousTraversalClass() {
         return Optional.empty();
@@ -450,6 +448,11 @@ public interface TraversalSource extends Cloneable {
     @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
     public TraversalSource clone();
 
+    @Override
+    public default void close() throws Exception {
+        // do nothing
+    }
+
     /**
      * @deprecated As of release 3.2.0. Please use {@link Graph#traversal(Class)}.
      */

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
index fdafb57..0525f8d 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSource.java
@@ -19,10 +19,10 @@
 package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
 
 import org.apache.commons.configuration.Configuration;
-import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.tinkerpop.gremlin.process.computer.Computer;
 import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
+import org.apache.tinkerpop.gremlin.process.remote.traversal.strategy.decoration.RemoteStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Bindings;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalEngine;
@@ -41,10 +41,8 @@ import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.structure.T;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
-import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -60,7 +58,7 @@ import java.util.function.UnaryOperator;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public class GraphTraversalSource implements TraversalSource {
-
+    protected transient RemoteConnection connection;
     protected final Graph graph;
     protected TraversalStrategies strategies;
     protected Bytecode bytecode = new Bytecode();
@@ -242,7 +240,19 @@ public class GraphTraversalSource implements TraversalSource {
 
     @Override
     public GraphTraversalSource withRemote(final RemoteConnection connection) {
-        return (GraphTraversalSource) TraversalSource.super.withRemote(connection);
+        try {
+            // check if someone called withRemote() more than once, so just release resources on the initial
+            // connection as you can't have more than one. maybe better to toss IllegalStateException??
+            if (this.connection != null)
+                this.connection.close();
+        } catch (Exception ignored) {
+            // not sure there's anything to do here
+        }
+
+        this.connection = connection;
+        final TraversalSource clone = this.clone();
+        clone.getStrategies().addStrategies(new RemoteStrategy(connection));
+        return (GraphTraversalSource) clone;
     }
 
     //// SPAWNS
@@ -309,6 +319,10 @@ public class GraphTraversalSource implements TraversalSource {
         return this.graph.tx();
     }
 
+    @Override
+    public void close() throws Exception {
+        if (connection != null) connection.close();
+    }
 
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
new file mode 100644
index 0000000..f9cf1df
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversalSourceTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.dsl.graph;
+
+import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GraphTraversalSourceTest {
+    @Test
+    public void shouldCloseRemoteConnectionOnWithRemote() throws Exception {
+        final RemoteConnection mock = mock(RemoteConnection.class);
+        final GraphTraversalSource g = EmptyGraph.instance().traversal().withRemote(mock);
+        g.close();
+
+        verify(mock, times(1)).close();
+    }
+
+    @Test
+    public void shouldNotAllowLeakRemoteConnectionsIfMultipleAreCreated() throws Exception {
+
+        final RemoteConnection mock1 = mock(RemoteConnection.class);
+        final RemoteConnection mock2 = mock(RemoteConnection.class);
+        final GraphTraversalSource g = EmptyGraph.instance().traversal().withRemote(mock1).withRemote(mock2);
+        g.close();
+
+        verify(mock1, times(1)).close();
+        verify(mock2, times(1)).close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
index 71abc77..14d89cc 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversal.java
@@ -46,6 +46,7 @@ public class DriverRemoteTraversal<S, E> extends AbstractRemoteTraversal<S, E> {
     private final Iterator<Traverser.Admin<E>> traversers;
     private Traverser.Admin<E> lastTraverser = EmptyTraverser.instance();
     private final RemoteTraversalSideEffects sideEffects;
+    private final Client client;
 
     public DriverRemoteTraversal(final ResultSet rs, final Client client, final boolean attach, final Optional<Configuration> conf) {
         // attaching is really just for testing purposes. it doesn't make sense in any real-world scenario as it would
@@ -59,6 +60,7 @@ public class DriverRemoteTraversal<S, E> extends AbstractRemoteTraversal<S, E> {
             this.traversers = new TraverserIterator<>(rs.iterator());
         }
 
+        this.client = client;
         this.sideEffects = new DriverRemoteTraversalSideEffects(
                 client,
                 rs.getOriginalRequestMessage().getRequestId(),
@@ -100,6 +102,17 @@ public class DriverRemoteTraversal<S, E> extends AbstractRemoteTraversal<S, E> {
         }
     }
 
+    /**
+     * Releases server-side resources related to this traversal (i.e. clearing the side-effect cache of data related to
+     * this traversal.
+     */
+    @Override
+    public void close() throws Exception {
+        sideEffects.close();
+
+        // leave the client open as it is owned by the DriverRemoteConnection not the traversal or side-effects
+    }
+
     static class TraverserIterator<E> implements Iterator<Traverser.Admin<E>> {
 
         private final Iterator<Result> inner;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/b7327186/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
index bd51e67..85d7abc 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/remote/DriverRemoteTraversalSideEffects.java
@@ -98,4 +98,11 @@ public class DriverRemoteTraversalSideEffects extends AbstractRemoteTraversalSid
 
         return keys;
     }
+
+    @Override
+    public void close() throws Exception {
+        // todo: need to add a call to "close" the side effects on the server - probably should ensure request only sends once
+
+        // leave the client open as it is owned by the DriverRemoteConnection not the traversal or side-effects
+    }
 }


[04/12] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-1464'

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1464'


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 3d178248eb732c61a3e8da57104f2f019324e6bc
Parents: ea7a515 66d206a
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 29 15:53:46 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Sep 29 15:53:46 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |   2 +
 .../gremlin/process/traversal/Bytecode.java     |   2 -
 .../structure/io/gryo/EntrySerializer.java      |  43 -----
 .../structure/io/gryo/GryoClassResolver.java    |   3 +
 .../gremlin/structure/io/gryo/GryoMapper.java   |  35 +++-
 .../structure/io/gryo/GryoSerializers.java      | 178 +++++++++++++++++--
 .../structure/io/gryo/PairSerializer.java       |  45 -----
 .../structure/io/gryo/URISerializer.java        |  49 -----
 .../structure/io/gryo/UUIDSerializer.java       |  50 ------
 .../structure/io/gryo/UtilSerializers.java      | 140 +++++++++++++++
 10 files changed, 337 insertions(+), 210 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3d178248/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index cced503,a3e21a1..8168053
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -48,14 -31,13 +48,16 @@@ TinkerPop 3.2.3 (Release Date: NOT OFFI
  * Fixed a bug in serialization of `Lambda` instances in GraphSON, which prevented their use in remote traversals.
  * Fixed a naming bug in Gremlin-Python where `P._and` and `P._or` should be `P.and_` and `P.or_`. (*breaking*)
  * `where()` predicate-based steps now support `by()`-modulation.
+ * Added Gryo serialization for `Bytecode`.
+ * Moved utility-based serializers to `UtilSerializers` for Gryo - these classes were private and hence this change is non-breaking.
  * `TraversalRing` returns a `null` if it does not contain traversals (previously `IdentityTraversal`).
 +* Deprecated `Graph.Exceptions.elementNotFoundException()` as it was not used in the code base outside of the test suite.
  * Fixed a `JavaTranslator` bug where `Bytecode` instructions were being mutated during translation.
  * Added `Path` to Gremlin-Python with respective GraphSON 2.0 deserializer.
 +* Added "keep-alive" functionality to the Java driver, which will send a heartbeat to the server when normal request activity on a connection stops for a period of time.
  * Renamed the `empty.result.indicator` preference to `result.indicator.null` in Gremlin Console
  * If `result.indicator.null` is set to an empty string, then no "result line" is printed in Gremlin Console.
 +* Deprecated `reconnectInitialDelay` on the Java driver.
  * VertexPrograms can now declare traverser requirements, e.g. to have access to the path when used with `.program()`.
  * New build options for `gremlin-python` where `-DglvPython` is no longer required.
  * Added missing `InetAddress` to GraphSON extension module.


[09/12] tinkerpop git commit: Added note to release docs about updating links on download page. CTR

Posted by sp...@apache.org.
Added note to release docs about updating links on download page. CTR


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 85ec40beb48fbec720d4bcaeac377eb411a2baba
Parents: 0070d3d
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Sep 30 13:05:06 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 13:05:06 2016 -0400

----------------------------------------------------------------------
 docs/src/dev/developer/release.asciidoc | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/85ec40be/docs/src/dev/developer/release.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/dev/developer/release.asciidoc b/docs/src/dev/developer/release.asciidoc
index f9baa94..086a2d4 100644
--- a/docs/src/dev/developer/release.asciidoc
+++ b/docs/src/dev/developer/release.asciidoc
@@ -152,6 +152,8 @@ Release & Promote
 . Copy release files from `dev/xx.yy.zz` to `release/xx.yy.zz`.
 . `cd release; svn add xx.yy.zz/; svn ci -m "TinkerPop xx.yy.zz release"`
 . Update homepage with references to latest distribution and to other internal links elsewhere on the page.
+.. On the link:http://tinkerpop.apache.org/downloads.html[Downloads] page, when moving "Current Releases" to "Archived
+Releases" recall that the hyperlink must change to point to version in the link:https://archive.apache.org/dist/tinkerpop/[Apache Archives].
 . Wait for Apache Sonatype to sync the artifacts to Maven Central at (link:http://repo1.maven.org/maven2/org/apache/tinkerpop/tinkerpop/[http://repo1.maven.org/maven2/org/apache/tinkerpop/tinkerpop/]).
 . Wait for zip distributions to to sync to the Apache mirrors (i.e ensure the download links work from a mirror).
 . If there are releases present in SVN that represents lines of code that are no longer under development, then remove those releases. In other words, if `3.2.0` is present and `3.2.1` is released then remove `3.2.0`.  However, if `3.1.3` is present and that line of code is still under potential development, it may stay.


[05/12] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-790'

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-790'

Conflicts:
	docs/src/upgrade/release-3.2.x-incubating.asciidoc


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 4fc05e8cbd484997a2613282870b68cf712d04e8
Parents: 3d17824 b732718
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 29 15:55:24 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Sep 29 15:55:24 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../src/reference/gremlin-applications.asciidoc | 10 +++-
 .../upgrade/release-3.2.x-incubating.asciidoc   | 25 +++++++++
 .../traversal/RemoteTraversalSideEffects.java   |  6 ++-
 .../gremlin/process/traversal/Traversal.java    |  7 ++-
 .../process/traversal/TraversalSource.java      | 15 +++---
 .../dsl/graph/GraphTraversalSource.java         | 24 +++++++--
 .../dsl/graph/GraphTraversalSourceTest.java     | 53 ++++++++++++++++++++
 .../driver/remote/DriverRemoteTraversal.java    | 13 +++++
 .../DriverRemoteTraversalSideEffects.java       |  7 +++
 10 files changed, 147 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/4fc05e8c/CHANGELOG.asciidoc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/4fc05e8c/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --cc docs/src/upgrade/release-3.2.x-incubating.asciidoc
index cc1cf2e,0615099..0ba09bd
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@@ -118,15 -118,31 +118,40 @@@ gremlin> g.V().hasLabel("software").cou
  TinkerPop 3.2.3 fixes this misbehavior and all `has()` method overloads behave like before, except that they no longer
  support no arguments.
  
 +Deprecated reconnectInitialDelay
 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 +
 +The `reconnectInitialDelay` setting on the `Cluster` builder has been deprecated. It no longer serves any purpose.
 +The value for the "initial delay" now comes from `reconnectInterval` (there are no longer two separate settings to
 +control).
 +
 +See: link:https://issues.apache.org/jira/browse/TINKERPOP-1460[TINKERPOP-1460]
 +
+ TraversalSource.close()
+ ^^^^^^^^^^^^^^^^^^^^^^^
+ 
+ `TraversalSource` now implements `AutoCloseable`, which means that the `close()` method is now available. This new
+ method is important in cases where `withRemote()` is used, as `withRemote()` can open "expensive" resources that need
+ to be released.
+ 
+ In the case of TinkerPop's `DriverRemoteConnection`, `close()` will destroy the `Client` instance that is created
+ internally by `withRemote()` as shown below:
+ 
+ [source,text]
+ ----
+ gremlin> graph = EmptyGraph.instance()
+ ==>emptygraph[empty]
+ gremlin> g = graph.traversal().withRemote('conf/remote-graph.properties')
+ ==>graphtraversalsource[emptygraph[empty], standard]
+ gremlin> g.close()
+ gremlin>
+ ----
+ 
+ Note that the `withRemote()` method will call `close()` on a `RemoteConnection` passed directly to it as well, so
+ there is no need to do that manually.
+ 
+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-790[TINKERPOP-790]
+ 
  Upgrading for Providers
  ~~~~~~~~~~~~~~~~~~~~~~~
  


[03/12] tinkerpop git commit: Centralized hamcrest, mockito, junit pom settings. CTR

Posted by sp...@apache.org.
Centralized hamcrest, mockito, junit pom settings. CTR


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: ea7a51564319ab68af7c7ffbf7b28068c324551e
Parents: d1ebe5f
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 29 15:40:55 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Sep 29 15:40:55 2016 -0400

----------------------------------------------------------------------
 giraph-gremlin/pom.xml                          |  1 -
 gremlin-benchmark/pom.xml                       |  2 -
 gremlin-console/pom.xml                         |  3 --
 gremlin-core/pom.xml                            |  8 +---
 ...aphSONMapperV2d0PartialEmbeddedTypeTest.java |  2 +-
 .../util/iterator/IteratorUtilsTest.java        | 12 +++---
 gremlin-driver/pom.xml                          |  3 --
 gremlin-groovy/pom.xml                          |  1 -
 .../groovy/engine/GremlinExecutorTest.java      | 11 ++---
 gremlin-python/pom.xml                          |  7 ----
 gremlin-server/pom.xml                          |  1 -
 gremlin-test/pom.xml                            | 17 --------
 .../ReadOnlyStrategyProcessTest.java            |  3 +-
 hadoop-gremlin/pom.xml                          |  1 -
 neo4j-gremlin/pom.xml                           |  1 -
 pom.xml                                         | 43 +++++++++++++++++++-
 spark-gremlin/pom.xml                           |  1 -
 tinkergraph-gremlin/pom.xml                     |  1 -
 18 files changed, 58 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/giraph-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/giraph-gremlin/pom.xml b/giraph-gremlin/pom.xml
index 528b2ad..ae3bdbc 100644
--- a/giraph-gremlin/pom.xml
+++ b/giraph-gremlin/pom.xml
@@ -178,7 +178,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-benchmark/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-benchmark/pom.xml b/gremlin-benchmark/pom.xml
index 303db15..536f6d6 100644
--- a/gremlin-benchmark/pom.xml
+++ b/gremlin-benchmark/pom.xml
@@ -37,7 +37,6 @@ limitations under the License.
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
             <scope>compile</scope>
         </dependency>
         <dependency>
@@ -69,7 +68,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <optional>true</optional>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-console/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-console/pom.xml b/gremlin-console/pom.xml
index aae5e41..f7b1fea 100644
--- a/gremlin-console/pom.xml
+++ b/gremlin-console/pom.xml
@@ -64,7 +64,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <optional>true</optional>
         </dependency>
         <dependency>
@@ -76,13 +75,11 @@ limitations under the License.
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest-all</artifactId>
-            <version>1.3</version>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-core/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-core/pom.xml b/gremlin-core/pom.xml
index baaaf77..6e256ae 100644
--- a/gremlin-core/pom.xml
+++ b/gremlin-core/pom.xml
@@ -65,36 +65,30 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
-            <version>${slf4j.version}</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>jcl-over-slf4j</artifactId>
-            <version>${slf4j.version}</version>
         </dependency>
         <!-- TESTING -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
-            <artifactId>mockito-all</artifactId>
-            <version>1.9.5</version>
+            <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest-all</artifactId>
-            <version>1.3</version>
             <scope>test</scope>
         </dependency>
         <!-- needed to test GraphFactory and xml based config via optional dependency in apache configurations -->

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0PartialEmbeddedTypeTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0PartialEmbeddedTypeTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0PartialEmbeddedTypeTest.java
index 7144ef4..28107d0 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0PartialEmbeddedTypeTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperV2d0PartialEmbeddedTypeTest.java
@@ -37,8 +37,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.fail;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtilsTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtilsTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtilsTest.java
index b5e7948..fe29913 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtilsTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/IteratorUtilsTest.java
@@ -26,12 +26,12 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import static org.hamcrest.CoreMatchers.hasItems;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -83,10 +83,11 @@ public class IteratorUtilsTest {
 
     @Test
     public void shouldIterateToSet() {
-        final Iterator<Integer> itty = Arrays.asList(1, 2, 3, 3, 2, 1).iterator();
+        final List<Integer> list = Arrays.asList(1, 2, 3, 3, 2, 1);
+        final Iterator<Integer> itty = list.iterator();
         final Set<Integer> set = IteratorUtils.set(itty);
         assertEquals(3, set.size());
-        assertThat(set, hasItems(1, 2, 3));
+        assertThat(set, is(new HashSet<>(list)));
     }
 
     @Test(expected = FastNoSuchElementException.class)
@@ -99,10 +100,11 @@ public class IteratorUtilsTest {
 
     @Test
     public void shouldFlatMapIterator() {
-        final Iterator<Iterator<Integer>> itty = Arrays.asList(Arrays.asList(1, 2, 3).iterator(), new ArrayList<Integer>().iterator(), Arrays.asList(4, 5, 6).iterator()).iterator();
+        final List<Iterator<Integer>> firstList = Arrays.asList(Arrays.asList(1, 2, 3).iterator(), new ArrayList<Integer>().iterator(), Arrays.asList(4, 5, 6).iterator());
+        final Iterator<Iterator<Integer>> itty = firstList.iterator();
         final List<Integer> list = IteratorUtils.list(IteratorUtils.flatMap(itty, x -> IteratorUtils.map(x, i -> i * 10)));
         assertEquals(6, list.size());
-        assertThat(list, hasItems(10, 20, 30, 40, 50, 60));
+        assertThat(list, is(Arrays.asList(10, 20, 30, 40, 50, 60)));
     }
 
     @Test(expected = FastNoSuchElementException.class)

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-driver/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-driver/pom.xml b/gremlin-driver/pom.xml
index d7fa1af..41e775c 100644
--- a/gremlin-driver/pom.xml
+++ b/gremlin-driver/pom.xml
@@ -65,13 +65,11 @@ limitations under the License.
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -83,7 +81,6 @@ limitations under the License.
         <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest-all</artifactId>
-            <version>1.3</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-groovy/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-groovy/pom.xml b/gremlin-groovy/pom.xml
index 171770f..d06aca7 100644
--- a/gremlin-groovy/pom.xml
+++ b/gremlin-groovy/pom.xml
@@ -74,7 +74,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
index b72b2c4..a56f805 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/engine/GremlinExecutorTest.java
@@ -49,12 +49,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.IntStream;
 
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
 import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsCollectionContaining.hasItem;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNot.not;
+import static org.hamcrest.number.OrderingComparison.greaterThan;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -518,8 +519,8 @@ public class GremlinExecutorTest {
                 .create();
 
         assertEquals(2, gremlinExecutor.eval("add(1,1)").get());
-        assertThat(gremlinExecutor.getGlobalBindings().keySet(), not(contains("someSet")));
         assertThat(gremlinExecutor.getGlobalBindings().keySet(), contains("name"));
+        assertThat(gremlinExecutor.getGlobalBindings().keySet(), not(hasItem("someSet")));
 
         assertEquals("stephen", gremlinExecutor.getGlobalBindings().get("name"));
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-python/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-python/pom.xml b/gremlin-python/pom.xml
index 24f1ca4..627b249 100644
--- a/gremlin-python/pom.xml
+++ b/gremlin-python/pom.xml
@@ -47,12 +47,6 @@
         </dependency>
         <!-- TESTING -->
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
             <groupId>org.apache.tinkerpop</groupId>
             <artifactId>tinkergraph-gremlin</artifactId>
             <version>${project.version}</version>
@@ -73,7 +67,6 @@
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-server/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-server/pom.xml b/gremlin-server/pom.xml
index cf05751..bbcb6c3 100644
--- a/gremlin-server/pom.xml
+++ b/gremlin-server/pom.xml
@@ -48,7 +48,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <optional>true</optional>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-test/pom.xml
----------------------------------------------------------------------
diff --git a/gremlin-test/pom.xml b/gremlin-test/pom.xml
index d1cfd04..e2c5ee7 100644
--- a/gremlin-test/pom.xml
+++ b/gremlin-test/pom.xml
@@ -46,38 +46,21 @@ limitations under the License.
             <artifactId>commons-io</artifactId>
             <version>2.4</version>
         </dependency>
-        <!-- TESTING -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.hamcrest</groupId>
-                    <artifactId>hamcrest-core</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>1.9.5</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.hamcrest</groupId>
-                    <artifactId>hamcrest-core</artifactId>
-                </exclusion>
-            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.hamcrest</groupId>
             <artifactId>hamcrest-all</artifactId>
-            <version>1.3</version>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <optional>true</optional>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyProcessTest.java
----------------------------------------------------------------------
diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyProcessTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyProcessTest.java
index d9c266f..5d97b6c 100644
--- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyProcessTest.java
+++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/verification/ReadOnlyStrategyProcessTest.java
@@ -26,9 +26,8 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSo
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.junit.Test;
 
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.core.StringStartsWith.startsWith;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.StringContains.containsString;
 import static org.junit.Assert.fail;
 
 /**

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/hadoop-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/hadoop-gremlin/pom.xml b/hadoop-gremlin/pom.xml
index 74f91b1..667c51e 100644
--- a/hadoop-gremlin/pom.xml
+++ b/hadoop-gremlin/pom.xml
@@ -152,7 +152,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/neo4j-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/neo4j-gremlin/pom.xml b/neo4j-gremlin/pom.xml
index 109f372..d324958 100644
--- a/neo4j-gremlin/pom.xml
+++ b/neo4j-gremlin/pom.xml
@@ -57,7 +57,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 020084b..632ed60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -135,7 +135,6 @@ limitations under the License.
     <properties>
         <commons.configuration.version>1.10</commons.configuration.version>
         <groovy.version>2.4.7</groovy.version>
-        <junit.version>4.12</junit.version>
         <metrics.version>3.0.2</metrics.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -622,6 +621,48 @@ limitations under the License.
                 <artifactId>log4j</artifactId>
                 <version>1.2.17</version>
             </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>4.12</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.hamcrest</groupId>
+                        <artifactId>hamcrest-core</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-core</artifactId>
+                <version>1.9.5</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.hamcrest</groupId>
+                        <artifactId>hamcrest-core</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.hamcrest</groupId>
+                <artifactId>hamcrest-all</artifactId>
+                <version>1.3</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-log4j12</artifactId>
+                <version>${slf4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>${slf4j.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>jcl-over-slf4j</artifactId>
+                <version>${slf4j.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/spark-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/spark-gremlin/pom.xml b/spark-gremlin/pom.xml
index 7f4137e..be9a9f2 100644
--- a/spark-gremlin/pom.xml
+++ b/spark-gremlin/pom.xml
@@ -312,7 +312,6 @@
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/ea7a5156/tinkergraph-gremlin/pom.xml
----------------------------------------------------------------------
diff --git a/tinkergraph-gremlin/pom.xml b/tinkergraph-gremlin/pom.xml
index 2b11884..c91ed17 100644
--- a/tinkergraph-gremlin/pom.xml
+++ b/tinkergraph-gremlin/pom.xml
@@ -52,7 +52,6 @@ limitations under the License.
         <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>


[08/12] tinkerpop git commit: Finalize variable. CTR

Posted by sp...@apache.org.
Finalize variable. CTR


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: f2b027beef8ec5a0dcd379dc2c68e4688bf73b03
Parents: 8d0d2f1
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Sep 30 13:01:11 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 13:01:24 2016 -0400

----------------------------------------------------------------------
 .../gremlin/server/op/traversal/TraversalOpProcessor.java          | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f2b027be/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
index e1534e2..80cacd2 100644
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/op/traversal/TraversalOpProcessor.java
@@ -231,7 +231,7 @@ public class TraversalOpProcessor extends AbstractOpProcessor {
         return aliases.get();
     }
 
-    private static Optional<Map<String, String>> validatedAliases(RequestMessage message) throws OpProcessorException {
+    private static Optional<Map<String, String>> validatedAliases(final RequestMessage message) throws OpProcessorException {
         final Optional<Map<String, String>> aliases = message.optionalArgs(Tokens.ARGS_ALIASES);
         if (!aliases.isPresent()) {
             final String msg = String.format("A message with [%s] op code requires a [%s] argument.", Tokens.OPS_BYTECODE, Tokens.ARGS_ALIASES);


[06/12] tinkerpop git commit: Corrected a number of problems in close() operations for the driver.

Posted by sp...@apache.org.
Corrected a number of problems in close() operations for the driver.

This was more of a commit than I wanted for tp31, but close() was really messed up. Fixed a number of race conditions and other logic that would allow the driver to hang on close. Also made it so that the Cluster makes an attempt to clean up any Client instances that it spawns.


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 6d14adb0819e2ede0b1e7794f384af2910fdbc84
Parents: 0070d3d
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Sep 29 08:40:07 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Sep 30 06:53:53 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  6 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 22 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 68 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 27 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index d0aa8e8..9f45477 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 TinkerPop 3.1.5 (Release Date: NOT OFFICIALLY RELEASED YET)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+* Improved handling of `Cluster.close()` and `Client.close()` to prevent the methods from hanging.
 * Fixed output redirection and potential memory leak in `GremlinGroovyScriptEngine`.
 * Corrected naming of `g_withPath_V_asXaX_out_out_mapXa_name_it_nameX` and `g_withPath_V_asXaX_out_mapXa_nameX` in `MapTest`.
 * Improved session cleanup when a close is triggered by the client.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/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 400ea10..6cf9fb2 100644
--- a/docs/src/upgrade/release-3.1.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.1.x-incubating.asciidoc
@@ -27,6 +27,23 @@ TinkerPop 3.1.5
 
 *Release Date: NOT OFFICIALLY RELEASED YET*
 
+Please see the link:https://github.com/apache/tinkerpop/blob/3.1.4/CHANGELOG.asciidoc#tinkerpop-315-release-date-XXXXXXXXXXXX[changelog] for a complete list of all the modifications that are part of this release.
+
+Upgrading for Users
+~~~~~~~~~~~~~~~~~~~
+
+Java Driver and close()
+^^^^^^^^^^^^^^^^^^^^^^^
+
+There were a few problems noted around the `close()` of `Cluster` and `Client` instances, including issues that
+presented as system hangs. These issues have been resolved, however, it is worth noting that an unchecked exception
+that was thrown under a certain situation has changed as part of the bug fixes. When submitting an in-session request
+on a `Client` that was closed (or closing) an `IllegalStateException` is thrown. This replaces older functionality
+that threw a `ConnectionException` and relied logic far deeper in the driver to produce that error and had the
+potential to open additional resources despite the intention of the user to "close".
+
+See: https://issues.apache.org/jira/browse/TINKERPOP-1467[TINKERPOP-1467]
+
 TinkerPop 3.1.4
 ---------------
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
index 40be11c..b3761b7 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
@@ -20,9 +20,6 @@ package org.apache.tinkerpop.gremlin.driver;
 
 import io.netty.channel.Channel;
 import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
-import io.netty.handler.ssl.SslContextBuilder;
-import io.netty.handler.ssl.SslProvider;
-import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinRequestEncoder;
 import org.apache.tinkerpop.gremlin.driver.handler.NioGremlinResponseDecoder;
@@ -42,7 +39,6 @@ import io.netty.handler.ssl.SslContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentMap;
@@ -156,7 +152,7 @@ public interface Channelizer extends ChannelHandler {
          */
         @Override
         public void close(final Channel channel) {
-            channel.writeAndFlush(new CloseWebSocketFrame());
+            if (channel.isOpen()) channel.writeAndFlush(new CloseWebSocketFrame());
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/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 4aca9ca..3a03141 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
@@ -36,6 +36,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 /**
@@ -245,6 +246,8 @@ public abstract class Client {
      * A low-level method that allows the submission of a manually constructed {@link RequestMessage}.
      */
     public CompletableFuture<ResultSet> submitAsync(final RequestMessage msg) {
+        if (isClosing()) throw new IllegalStateException("Client has been closed");
+
         if (!initialized)
             init();
 
@@ -269,6 +272,8 @@ public abstract class Client {
         }
     }
 
+    public abstract boolean isClosing();
+
     /**
      * Closes the client by making a synchronous call to {@link #closeAsync()}.
      */
@@ -290,11 +295,17 @@ public abstract class Client {
     public final static class ClusteredClient extends Client {
 
         private ConcurrentMap<Host, ConnectionPool> hostConnectionPools = new ConcurrentHashMap<>();
+        private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
 
         ClusteredClient(final Cluster cluster) {
             super(cluster);
         }
 
+        @Override
+        public boolean isClosing() {
+            return closing.get() != null;
+        }
+
         /**
          * Submits a Gremlin script to the server and returns a {@link ResultSet} once the write of the request is
          * complete.
@@ -364,10 +375,14 @@ public abstract class Client {
          * Closes all the connection pools on all hosts.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
+        public synchronized CompletableFuture<Void> closeAsync() {
+            if (closing.get() != null)
+                return closing.get();
+
             final CompletableFuture[] poolCloseFutures = new CompletableFuture[hostConnectionPools.size()];
             hostConnectionPools.values().stream().map(ConnectionPool::closeAsync).collect(Collectors.toList()).toArray(poolCloseFutures);
-            return CompletableFuture.allOf(poolCloseFutures);
+            closing.set(CompletableFuture.allOf(poolCloseFutures));
+            return closing.get();
         }
     }
 
@@ -448,11 +463,16 @@ public abstract class Client {
          * close on the {@code Client} that created it.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
+        public synchronized CompletableFuture<Void> closeAsync() {
             close.complete(null);
             return close;
         }
 
+        @Override
+        public boolean isClosing() {
+            return close.isDone();
+        }
+
         /**
          * {@inheritDoc}
          */
@@ -483,6 +503,8 @@ public abstract class Client {
 
         private ConnectionPool connectionPool;
 
+        private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
+
         SessionedClient(final Cluster cluster, final String sessionId, final boolean manageTransactions) {
             super(cluster);
             this.sessionId = sessionId;
@@ -526,12 +548,22 @@ public abstract class Client {
             connectionPool = new ConnectionPool(host, this, Optional.of(1), Optional.of(1));
         }
 
+        @Override
+        public boolean isClosing() {
+            return closing.get() != null;
+        }
+
         /**
          * Close the bound {@link ConnectionPool}.
          */
         @Override
-        public CompletableFuture<Void> closeAsync() {
-            return connectionPool.closeAsync();
+        public synchronized CompletableFuture<Void> closeAsync() {
+            if (closing.get() != null)
+                return closing.get();
+
+            final CompletableFuture<Void> connectionPoolClose = connectionPool.closeAsync();
+            closing.set(connectionPoolClose);
+            return connectionPoolClose;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/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 6a6a2e3..473991a 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
@@ -36,6 +36,7 @@ import javax.net.ssl.TrustManager;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.lang.ref.WeakReference;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.URI;
@@ -83,7 +84,9 @@ public final class Cluster {
      * submitted or can be directly initialized via {@link Client#init()}.
      */
     public <T extends Client> T connect() {
-        return (T) new Client.ClusteredClient(this);
+        final Client client = new Client.ClusteredClient(this);
+        manager.trackClient(client);
+        return (T) client;
     }
 
     /**
@@ -122,7 +125,9 @@ public final class Cluster {
     public <T extends Client> T connect(final String sessionId, final boolean manageTransactions) {
         if (null == sessionId || sessionId.isEmpty())
             throw new IllegalArgumentException("sessionId cannot be null or empty");
-        return (T) new Client.SessionedClient(this, sessionId, manageTransactions);
+        final Client client = new Client.SessionedClient(this, sessionId, manageTransactions);
+        manager.trackClient(client);
+        return (T) client;
     }
 
     @Override
@@ -684,6 +689,8 @@ public final class Cluster {
 
         private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
 
+        private final List<WeakReference<Client>> openedClients = new ArrayList<>();
+
         private Manager(final Builder builder) {
             this.loadBalancingStrategy = builder.loadBalancingStrategy;
             this.authProps = builder.authProps;
@@ -730,6 +737,10 @@ public final class Cluster {
             });
         }
 
+        void trackClient(final Client client) {
+            openedClients.add(new WeakReference<>(client));
+        }
+
         public Host add(final InetSocketAddress address) {
             final Host newHost = new Host(address, Cluster.this);
             final Host previous = hosts.putIfAbsent(address, newHost);
@@ -745,6 +756,13 @@ public final class Cluster {
             if (closeFuture.get() != null)
                 return closeFuture.get();
 
+            for (WeakReference<Client> openedClient : openedClients) {
+                final Client client = openedClient.get();
+                if (client != null && !client.isClosing()) {
+                    client.close();
+                }
+            }
+
             final CompletableFuture<Void> closeIt = new CompletableFuture<>();
             closeFuture.set(closeIt);
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 220ad42..660ad0d 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
@@ -35,6 +35,8 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -128,7 +130,7 @@ final class Connection {
         return isDead;
     }
 
-    public boolean isClosed() {
+    boolean isClosing() {
         return closeFuture.get() != null;
     }
 
@@ -148,22 +150,26 @@ final class Connection {
         return pending;
     }
 
-    public CompletableFuture<Void> closeAsync() {
+    public synchronized CompletableFuture<Void> closeAsync() {
+        if (isClosing()) return closeFuture.get();
+
         final CompletableFuture<Void> future = new CompletableFuture<>();
-        if (!closeFuture.compareAndSet(null, future))
-            return closeFuture.get();
+        closeFuture.set(future);
 
         // make sure all requests in the queue are fully processed before killing.  if they are then shutdown
         // can be immediate.  if not this method will signal the readCompleted future defined in the write()
         // operation to check if it can close.  in this way the connection no longer receives writes, but
         // can continue to read. If a request never comes back the future won't get fulfilled and the connection
         // will maintain a "pending" request, that won't quite ever go away.  The build up of such a dead requests
-        // on a connection in the connection pool will force the pool to replace the connection for a fresh one
-        if (pending.isEmpty()) {
+        // on a connection in the connection pool will force the pool to replace the connection for a fresh one.
+        if (isOkToClose()) {
             if (null == channel)
                 future.complete(null);
             else
                 shutdown(future);
+        } else {
+            // there may be some pending requests. schedule a job to wait for those to complete and then shutdown
+            new CheckForPending(future).runUntilDone(cluster.executor(), 1000, TimeUnit.MILLISECONDS);
         }
 
         return future;
@@ -247,16 +253,20 @@ final class Connection {
         }
     }
 
+    private boolean isOkToClose() {
+        return pending.isEmpty() || (channel !=null && !channel.isOpen()) || !pool.host.isAvailable();
+    }
+
     /**
      * Close was signaled in closeAsync() but there were pending messages at that time. This method attempts the
      * shutdown if the returned result cleared up the last pending message.
      */
     private void tryShutdown() {
-        if (isClosed() && pending.isEmpty())
+        if (isClosing() && isOkToClose())
             shutdown(closeFuture.get());
     }
 
-    private void shutdown(final CompletableFuture<Void> future) {
+    private synchronized void shutdown(final CompletableFuture<Void> future) {
         // shutdown can be called directly from closeAsync() or after write() and therefore this method should only
         // be called once. once shutdown is initiated, it shouldn't be executed a second time or else it sends more
         // messages at the server and leads to ugly log messages over there.
@@ -286,6 +296,7 @@ final class Connection {
             }
 
             channelizer.close(channel);
+
             final ChannelPromise promise = channel.newPromise();
             promise.addListener(f -> {
                 if (f.cause() != null)
@@ -307,4 +318,45 @@ final class Connection {
     public String toString() {
         return connectionLabel;
     }
+
+    /**
+     * Self-cancelling tasks that periodically checks for the pending queue to clear before shutting down the
+     * {@code Connection}. Once it does that, it self cancels the scheduled job in the executor.
+     */
+    private final class CheckForPending implements Runnable {
+        private volatile ScheduledFuture<?> self;
+        private final CompletableFuture<Void> future;
+
+        CheckForPending(final CompletableFuture<Void> future) {
+            this.future = future;
+        }
+
+        @Override
+        public void run() {
+            logger.info("Checking for pending messages to complete before close on {}", this);
+
+            if (isOkToClose()) {
+                shutdown(future);
+                boolean interrupted = false;
+                try {
+                    while(null == self) {
+                        try {
+                            Thread.sleep(1);
+                        } catch (InterruptedException e) {
+                            interrupted = true;
+                        }
+                    }
+                    self.cancel(false);
+                } finally {
+                    if(interrupted) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        }
+
+        void runUntilDone(final ScheduledExecutorService executor, final long period, final TimeUnit unit) {
+            self = executor.scheduleAtFixedRate(this, period, period, unit);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
index 9955e82..4691b1b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
@@ -219,27 +219,26 @@ final class ConnectionPool {
     /**
      * Permanently kills the pool.
      */
-    public CompletableFuture<Void> closeAsync() {
-        logger.info("Signalled closing of connection pool on {} with core size of {}", host, minPoolSize);
+    public synchronized CompletableFuture<Void> closeAsync() {
+        if (closeFuture.get() != null) return closeFuture.get();
 
-        CompletableFuture<Void> future = closeFuture.get();
-        if (future != null)
-            return future;
+        logger.info("Signalled closing of connection pool on {} with core size of {}", host, minPoolSize);
 
         announceAllAvailableConnection();
-        future = CompletableFuture.allOf(killAvailableConnections());
-
-        return closeFuture.compareAndSet(null, future) ? future : closeFuture.get();
+        final CompletableFuture<Void> future = killAvailableConnections();
+        closeFuture.set(future);
+        return future;
     }
 
-    private CompletableFuture[] killAvailableConnections() {
+    private CompletableFuture<Void> killAvailableConnections() {
         final List<CompletableFuture<Void>> futures = new ArrayList<>(connections.size());
         for (Connection connection : connections) {
             final CompletableFuture<Void> future = connection.closeAsync();
-            future.thenRunAsync(open::decrementAndGet, cluster.executor());
+            future.thenRun(open::decrementAndGet);
             futures.add(future);
         }
-        return futures.toArray(new CompletableFuture[futures.size()]);
+
+        return CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
     }
 
     void replaceConnection(final Connection connection) {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
index 773322a..65eb662 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
@@ -29,11 +29,11 @@ import io.netty.util.Attribute;
 import io.netty.util.AttributeKey;
 import io.netty.util.ReferenceCountUtil;
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.net.InetSocketAddress;
-import java.nio.charset.StandardCharsets;
 import java.security.PrivilegedExceptionAction;
 import java.security.PrivilegedActionException;
 import java.util.HashMap;
@@ -83,11 +83,24 @@ final class Handler {
             if (response.getStatus().getCode() == ResponseStatusCode.AUTHENTICATE) {
                 final Attribute<SaslClient> saslClient = channelHandlerContext.attr(saslClientKey);
                 final Attribute<Subject> subject = channelHandlerContext.attr(subjectKey);
-                RequestMessage.Builder messageBuilder = RequestMessage.build(Tokens.OPS_AUTHENTICATION);
+                final RequestMessage.Builder messageBuilder = RequestMessage.build(Tokens.OPS_AUTHENTICATION);
                 // First time through we don't have a sasl client
                 if (saslClient.get() == null) {
                     subject.set(login());
-                    saslClient.set(saslClient(getHostName(channelHandlerContext)));
+                    try {
+                        saslClient.set(saslClient(getHostName(channelHandlerContext)));
+                    } catch (SaslException saslException) {
+                        // push the sasl error into a failure response from the server. this ensures that standard
+                        // processing for the ResultQueue is kept. without this SaslException trap and subsequent
+                        // conversion to an authentication failure, the close() of the connection might not
+                        // succeed as it will appear as though pending messages remain present in the queue on the
+                        // connection and the shutdown won't proceed
+                        final ResponseMessage clientSideError = ResponseMessage.build(response.getRequestId())
+                                .code(ResponseStatusCode.FORBIDDEN).statusMessage(saslException.getMessage()).create();
+                        channelHandlerContext.fireChannelRead(clientSideError);
+                        return;
+                    }
+
                     messageBuilder.addArg(Tokens.ARGS_SASL_MECHANISM, getMechanism());
                     messageBuilder.addArg(Tokens.ARGS_SASL, saslClient.get().hasInitialResponse() ?
                                                                 evaluateChallenge(subject, saslClient, NULL_CHALLENGE) : null);
@@ -214,12 +227,12 @@ final class Handler {
             // there are that many failures someone would take notice and hopefully stop the client.
             logger.error("Could not process the response", cause);
 
-            // the channel took an error because of something pretty bad so release all the completeable
-            // futures out there
-            pending.entrySet().stream().forEach(kv -> kv.getValue().markError(cause));
+            // the channel took an error because of something pretty bad so release all the futures out there
+            pending.values().forEach(val -> val.markError(cause));
+            pending.clear();
 
             // serialization exceptions should not close the channel - that's worth a retry
-            if (!ExceptionUtils.getThrowableList(cause).stream().anyMatch(t -> t instanceof SerializationException))
+            if (!IteratorUtils.anyMatch(ExceptionUtils.getThrowableList(cause).iterator(), t -> t instanceof SerializationException))
                 ctx.close();
         }
     }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
index 89a0225..e55456e 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
@@ -76,6 +76,10 @@ final class ResultQueue {
         return this.size() == 0;
     }
 
+    public boolean isComplete() {
+        return readComplete.isDone();
+    }
+
     void drainTo(final Collection<Result> collection) {
         if (error.get() != null) throw new RuntimeException(error.get());
         resultLinkedBlockingQueue.drainTo(collection);

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
----------------------------------------------------------------------
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
index 922775e..e2a5668 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
@@ -95,9 +95,9 @@ public final class WebSocketClientHandler extends SimpleChannelInboundHandler<Ob
 
     @Override
     public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
-        logger.warn("Exception caught during WebSocket processing - closing connection", cause);
         if (!handshakeFuture.isDone()) handshakeFuture.setFailure(cause);
-        ctx.close();
+
+        // let the GremlinResponseHandler take care of exception logging, channel closing, and cleanup
         ctx.fireExceptionCaught(cause);
     }
 }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/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 1a04b6b..bf66b0d 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
@@ -25,7 +25,6 @@ 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.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer;
@@ -746,11 +745,13 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
         client.close();
 
         try {
-            client.submit("x[0]+1");
+            client.submit("x[0]+1").all().get();
             fail("Should have thrown an exception because the connection is closed");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root, instanceOf(ConnectionException.class));
+            assertThat(root, instanceOf(IllegalStateException.class));
+        } finally {
+            cluster.close();
         }
     }
 
@@ -1248,6 +1249,78 @@ public class GremlinDriverIntegrateTest extends AbstractGremlinServerIntegration
         }
     }
 
+    @Test
+    public void shouldCloseAllClientsOnCloseOfCluster() throws Exception {
+        final Cluster cluster = Cluster.open();
+        final Client sessionlessOne = cluster.connect();
+        final Client session = cluster.connect("session");
+        final Client sessionlessTwo = cluster.connect();
+        final Client sessionlessThree = cluster.connect();
+        final Client sessionlessFour = cluster.connect();
+
+        assertEquals(2, sessionlessOne.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, session.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, sessionlessTwo.submit("1+1").all().get().get(0).getInt());
+        assertEquals(2, sessionlessThree.submit("1+1").all().get().get(0).getInt());
+        // dont' send anything on the 4th client
+
+        // close one of these Clients before the Cluster
+        sessionlessThree.close();
+        cluster.close();
+
+        try {
+            sessionlessOne.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            session.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessTwo.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessThree.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        try {
+            sessionlessFour.submit("1+1").all().get();
+            fail("Should have tossed an exception because cluster was closed");
+        } catch (Exception ex) {
+            final Throwable root = ExceptionUtils.getRootCause(ex);
+            assertThat(root, instanceOf(IllegalStateException.class));
+            assertEquals("Client has been closed", root.getMessage());
+        }
+
+        // allow call to close() even though closed through cluster
+        sessionlessOne.close();
+        session.close();
+        sessionlessTwo.close();
+
+        cluster.close();
+    }
+
     private void assertFutureTimeout(final CompletableFuture<List<Result>> futureFirst) {
         try
         {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
index 3e1b7e9..887d408 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthIntegrateTest.java
@@ -23,7 +23,6 @@ import org.apache.tinkerpop.gremlin.driver.Client;
 import org.apache.tinkerpop.gremlin.driver.Cluster;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
-import org.ietf.jgss.GSSException;
 import org.junit.Test;
 
 import java.util.HashMap;
@@ -128,7 +127,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
             fail("This should not succeed as the client did not provide credentials");
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertEquals(GSSException.class, root.getClass());
+            assertEquals(ResponseException.class, root.getClass());
         } finally {
             cluster.close();
         }
@@ -157,7 +156,7 @@ public class GremlinServerAuthIntegrateTest extends AbstractGremlinServerIntegra
         final Client client = cluster.connect();
 
         try {
-            client.submit("1+1").all();
+            client.submit("1+1").all().get();
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertEquals(ResponseException.class, root.getClass());

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
index f2e5622..2f332be 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerAuthOldIntegrateTest.java
@@ -131,7 +131,7 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
             fail("This should not succeed as the client did not provide credentials");
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertEquals(GSSException.class, root.getClass());
+            assertEquals(ResponseException.class, root.getClass());
 
             // removed this assert as the text of the message changes based on kerberos config - stupid kerberos
             // assertThat(root.getMessage(), startsWith("Invalid name provided"));
@@ -163,7 +163,7 @@ public class GremlinServerAuthOldIntegrateTest extends AbstractGremlinServerInte
         final Client client = cluster.connect();
 
         try {
-            client.submit("1+1").all();
+            client.submit("1+1").all().get();
         } catch(Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
             assertEquals(ResponseException.class, root.getClass());

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/6d14adb0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
index 99b3a1b..3c1fef9 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerSessionIntegrateTest.java
@@ -26,7 +26,6 @@ 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.driver.Tokens;
-import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException;
 import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
@@ -189,7 +188,7 @@ public class GremlinServerSessionIntegrateTest  extends AbstractGremlinServerInt
             fail("Session should be dead");
         } catch (Exception ex) {
             final Throwable root = ExceptionUtils.getRootCause(ex);
-            assertThat(root, instanceOf(ConnectionException.class));
+            assertThat(root, instanceOf(IllegalStateException.class));
         } finally {
             cluster.close();
         }
@@ -229,7 +228,8 @@ public class GremlinServerSessionIntegrateTest  extends AbstractGremlinServerInt
             cluster.close();
         }
 
-        assertEquals(1, recordingAppender.getMessages().stream()
+        // there will be on for the timeout and a second for closing the cluster
+        assertEquals(2, recordingAppender.getMessages().stream()
                 .filter(msg -> msg.equals("INFO - Session shouldHaveTheSessionTimeout closed\n")).count());
     }
 


[12/12] tinkerpop git commit: Merge remote-tracking branch 'origin/TINKERPOP-1467' into TINKERPOP-1467-master

Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1467' into TINKERPOP-1467-master

Conflicts:
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
	gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java


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

Branch: refs/heads/TINKERPOP-1467-master
Commit: 9d860ca0c880bf7d8c974df4d021266d1868dcf0
Parents: 233a6ba 6d14adb
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Sat Oct 1 05:48:21 2016 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Sat Oct 1 05:48:21 2016 -0400

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  1 +
 .../upgrade/release-3.1.x-incubating.asciidoc   | 17 +++++
 .../tinkerpop/gremlin/driver/Channelizer.java   |  2 +-
 .../apache/tinkerpop/gremlin/driver/Client.java | 42 +++++++++--
 .../tinkerpop/gremlin/driver/Cluster.java       | 24 +++++-
 .../tinkerpop/gremlin/driver/Connection.java    | 67 +++++++++++++++--
 .../gremlin/driver/ConnectionPool.java          | 21 +++---
 .../tinkerpop/gremlin/driver/Handler.java       | 26 +++++--
 .../tinkerpop/gremlin/driver/ResultQueue.java   |  4 +
 .../driver/handler/WebSocketClientHandler.java  |  4 +-
 .../server/GremlinDriverIntegrateTest.java      | 79 +++++++++++++++++++-
 .../server/GremlinServerAuthIntegrateTest.java  |  5 +-
 .../GremlinServerAuthOldIntegrateTest.java      |  4 +-
 .../GremlinServerSessionIntegrateTest.java      |  6 +-
 14 files changed, 255 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/CHANGELOG.asciidoc
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Channelizer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Client.java
index 7b9262e,3a03141..bd397a1
--- 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
@@@ -350,11 -295,17 +355,17 @@@ public abstract class Client 
      public final static class ClusteredClient extends Client {
  
          private ConcurrentMap<Host, ConnectionPool> hostConnectionPools = new ConcurrentHashMap<>();
+         private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
  
 -        ClusteredClient(final Cluster cluster) {
 -            super(cluster);
 +        ClusteredClient(final Cluster cluster, final Client.Settings settings) {
 +            super(cluster, settings);
          }
  
+         @Override
+         public boolean isClosing() {
+             return closing.get() != null;
+         }
+ 
          /**
           * Submits a Gremlin script to the server and returns a {@link ResultSet} once the write of the request is
           * complete.
@@@ -650,10 -503,12 +670,12 @@@
  
          private ConnectionPool connectionPool;
  
+         private final AtomicReference<CompletableFuture<Void>> closing = new AtomicReference<>(null);
+ 
 -        SessionedClient(final Cluster cluster, final String sessionId, final boolean manageTransactions) {
 -            super(cluster);
 -            this.sessionId = sessionId;
 -            this.manageTransactions = manageTransactions;
 +        SessionedClient(final Cluster cluster, final Client.Settings settings) {
 +            super(cluster, settings);
 +            this.sessionId = settings.getSession().get().sessionId;
 +            this.manageTransactions = settings.getSession().get().manageTransactions;
          }
  
          String getSessionId() {
@@@ -697,134 -557,13 +724,139 @@@
           * Close the bound {@link ConnectionPool}.
           */
          @Override
-         public CompletableFuture<Void> closeAsync() {
-             return connectionPool.closeAsync();
+         public synchronized CompletableFuture<Void> closeAsync() {
+             if (closing.get() != null)
+                 return closing.get();
+ 
+             final CompletableFuture<Void> connectionPoolClose = connectionPool.closeAsync();
+             closing.set(connectionPoolClose);
+             return connectionPoolClose;
          }
      }
 +
 +    /**
 +     * Settings given to {@link Cluster#connect(Settings)} that configures how a {@link Client} will behave.
 +     */
 +    public static class Settings {
 +        private final Optional<SessionSettings> session;
 +
 +        private Settings(final Builder builder) {
 +            this.session = builder.session;
 +        }
 +
 +        public static Builder build() {
 +            return new Builder();
 +        }
 +
 +        /**
 +         * Determines if the {@link Client} is to be constructed with a session. If the value is present, then a
 +         * session is expected.
 +         */
 +        public Optional<SessionSettings> getSession() {
 +            return session;
 +        }
 +
 +        public static class Builder {
 +            private Optional<SessionSettings> session = Optional.empty();
 +
 +            private Builder() {}
 +
 +            /**
 +             * Enables a session. By default this will create a random session name and configure transactions to be
 +             * unmanaged. This method will override settings provided by calls to the other overloads of
 +             * {@code useSession}.
 +             */
 +            public Builder useSession(final boolean enabled) {
 +                session = enabled ? Optional.of(SessionSettings.build().create()) : Optional.empty();
 +                return this;
 +            }
 +
 +            /**
 +             * Enables a session. By default this will create a session with the provided name and configure
 +             * transactions to be unmanaged. This method will override settings provided by calls to the other
 +             * overloads of {@code useSession}.
 +             */
 +            public Builder useSession(final String sessionId) {
 +                session = sessionId != null && !sessionId.isEmpty() ?
 +                        Optional.of(SessionSettings.build().sessionId(sessionId).create()) : Optional.empty();
 +                return this;
 +            }
 +
 +            /**
 +             * Enables a session. This method will override settings provided by calls to the other overloads of
 +             * {@code useSession}.
 +             */
 +            public Builder useSession(final SessionSettings settings) {
 +                session = Optional.ofNullable(settings);
 +                return this;
 +            }
 +
 +            public Settings create() {
 +                return new Settings(this);
 +            }
 +
 +        }
 +    }
 +
 +    /**
 +     * Settings for a {@link Client} that involve a session.
 +     */
 +    public static class SessionSettings {
 +        private final boolean manageTransactions;
 +        private final String sessionId;
 +
 +        private SessionSettings(final Builder builder) {
 +            manageTransactions = builder.manageTransactions;
 +            sessionId = builder.sessionId;
 +        }
 +
 +        /**
 +         * If enabled, transactions will be "managed" such that each request will represent a complete transaction.
 +         */
 +        public boolean manageTransactions() {
 +            return manageTransactions;
 +        }
 +
 +        /**
 +         * Provides the identifier of the session.
 +         */
 +        public String getSessionId() {
 +            return sessionId;
 +        }
 +
 +        public static SessionSettings.Builder build() {
 +            return new SessionSettings.Builder();
 +        }
 +
 +        public static class Builder {
 +            private boolean manageTransactions = false;
 +            private String sessionId = UUID.randomUUID().toString();
 +
 +            private Builder() {}
 +
 +            /**
 +             * If enabled, transactions will be "managed" such that each request will represent a complete transaction.
 +             * By default this value is {@code false}.
 +             */
 +            public Builder manageTransactions(final boolean manage) {
 +                manageTransactions = manage;
 +                return this;
 +            }
 +
 +            /**
 +             * Provides the identifier of the session. This value cannot be null or empty. By default it is set to
 +             * a random {@code UUID}.
 +             */
 +            public Builder sessionId(final String sessionId) {
 +                if (null == sessionId || sessionId.isEmpty())
 +                    throw new IllegalArgumentException("sessionId cannot be null or empty");
 +                this.sessionId = sessionId;
 +                return this;
 +            }
 +
 +            public SessionSettings create() {
 +                return new SessionSettings(this);
 +            }
 +        }
 +    }
  }

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Cluster.java
index b9a3cee,473991a..567bfb4
--- 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
@@@ -84,7 -84,9 +85,9 @@@ public final class Cluster 
       * submitted or can be directly initialized via {@link Client#init()}.
       */
      public <T extends Client> T connect() {
-         return (T) new Client.ClusteredClient(this, Client.Settings.build().create());
 -        final Client client = new Client.ClusteredClient(this);
++        final Client client = new Client.ClusteredClient(this, Client.Settings.build().create());
+         manager.trackClient(client);
+         return (T) client;
      }
  
      /**
@@@ -121,19 -123,11 +124,21 @@@
       * @param manageTransactions enables auto-transactions when set to true
       */
      public <T extends Client> T connect(final String sessionId, final boolean manageTransactions) {
 -        if (null == sessionId || sessionId.isEmpty())
 -            throw new IllegalArgumentException("sessionId cannot be null or empty");
 -        final Client client = new Client.SessionedClient(this, sessionId, manageTransactions);
 +        final Client.SessionSettings sessionSettings = Client.SessionSettings.build()
 +                .manageTransactions(manageTransactions)
 +                .sessionId(sessionId).create();
 +        final Client.Settings settings = Client.Settings.build().useSession(sessionSettings).create();
 +        return connect(settings);
 +    }
 +
 +    /**
 +     * Creates a new {@link Client} based on the settings provided.
 +     */
 +    public <T extends Client> T connect(final Client.Settings settings) {
-         return settings.getSession().isPresent() ? (T) new Client.SessionedClient(this, settings) :
-                 (T) new Client.ClusteredClient(this, settings);
++        final Client client = settings.getSession().isPresent() ? new Client.SessionedClient(this, settings) :
++                new Client.ClusteredClient(this, settings);
+         manager.trackClient(client);
+         return (T) client;
      }
  
      @Override
@@@ -863,15 -687,11 +868,17 @@@
  
          private final ScheduledExecutorService executor;
  
 +        private final int nioPoolSize;
 +        private final int workerPoolSize;
 +        private final int port;
 +
          private final AtomicReference<CompletableFuture<Void>> closeFuture = new AtomicReference<>();
  
+         private final List<WeakReference<Client>> openedClients = new ArrayList<>();
+ 
          private Manager(final Builder builder) {
 +            validateBuilder(builder);
 +
              this.loadBalancingStrategy = builder.loadBalancingStrategy;
              this.authProps = builder.authProps;
              this.contactPoints = builder.getContactPoints();

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
----------------------------------------------------------------------
diff --cc gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
index 02ec0b3,660ad0d..2a68032
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Connection.java
@@@ -158,15 -150,12 +159,16 @@@ final class Connection 
          return pending;
      }
  
-     public CompletableFuture<Void> closeAsync() {
+     public synchronized CompletableFuture<Void> closeAsync() {
+         if (isClosing()) return closeFuture.get();
+ 
          final CompletableFuture<Void> future = new CompletableFuture<>();
-         if (!closeFuture.compareAndSet(null, future))
-             return closeFuture.get();
+         closeFuture.set(future);
  
 +        // stop any pings being sent at the server for keep-alive
 +        final ScheduledFuture keepAlive = keepAliveFuture.get();
 +        if (keepAlive != null) keepAlive.cancel(true);
 +
          // make sure all requests in the queue are fully processed before killing.  if they are then shutdown
          // can be immediate.  if not this method will signal the readCompleted future defined in the write()
          // operation to check if it can close.  in this way the connection no longer receives writes, but

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ConnectionPool.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/Handler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ResultQueue.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/handler/WebSocketClientHandler.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9d860ca0/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
----------------------------------------------------------------------
diff --cc gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinDriverIntegrateTest.java
index 96cde54,bf66b0d..d8aff4a
--- 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
@@@ -26,9 -25,7 +26,8 @@@ import org.apache.tinkerpop.gremlin.dri
  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.driver.exception.ConnectionException;
  import org.apache.tinkerpop.gremlin.driver.exception.ResponseException;
 +import org.apache.tinkerpop.gremlin.driver.handler.WebSocketClientHandler;
  import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
  import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer;
  import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0;