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 2020/11/06 19:34:08 UTC

[tinkerpop] branch TINKERPOP-2461 updated (8043a7d -> 127821e)

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a change to branch TINKERPOP-2461
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


 discard 8043a7d  TINKERPOP-2461 Added reference documentation for Translator
 discard 67b16ba  TINKERPOP-2461 Added upgrade docs
 discard c7ab06d  TINKERPOP-2461 Aligned CoreImports with GroovyTranslator
 discard bb784e3  TINKERPOP-2443 Provided more succinct syntax for withStrategies()
     new 19411e2  TINKERPOP-2466 Provided more succinct syntax for withStrategies()
     new c666e0b  TINKERPOP-2461 Aligned CoreImports with GroovyTranslator
     new 9145537  TINKERPOP-2461 Added upgrade docs
     new 127821e  TINKERPOP-2461 Added reference documentation for Translator

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (8043a7d)
            \
             N -- N -- N   refs/heads/TINKERPOP-2461 (127821e)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:


[tinkerpop] 03/04: TINKERPOP-2461 Added upgrade docs

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2461
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 9145537fb9916cc74679ce33d8927d5ddf78d0c8
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Nov 5 16:20:17 2020 -0500

    TINKERPOP-2461 Added upgrade docs
---
 docs/src/upgrade/release-3.4.x.asciidoc            | 77 ++++++++++++++++++++--
 .../gremlin/process/traversal/Translator.java      |  7 ++
 2 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/docs/src/upgrade/release-3.4.x.asciidoc b/docs/src/upgrade/release-3.4.x.asciidoc
index 19ae29e..0ce2ac5 100644
--- a/docs/src/upgrade/release-3.4.x.asciidoc
+++ b/docs/src/upgrade/release-3.4.x.asciidoc
@@ -28,15 +28,68 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 Please see the link:https://github.com/apache/tinkerpop/blob/3.4.9/CHANGELOG.asciidoc#release-3-4-9[changelog] for a
 complete list of all the modifications that are part of this release.
 
-=== GraphManager Extension
+=== Translator Implementations
 
-The `org.apache.tinkerpop.gremlin.server.util.CheckedGraphManager` can be used instead of 
-`org.apache.tinkerpop.gremlin.server.util.DefaultGraphManager` (in gremlin-server.yml  to ensures that Gremlin Server
-fails to start if all graphs fails. This configuration option can be useful for a number of different situations (e.g.
-use `CheckedGraphManager` on a Kubernetes cluster to ensure that a pod will be restarted when it cannot properly handle
-requests.) As a final note, `DefaultGraphManager` is no longer `final` and thus can be extended.
+One of the silent features of Gremlin is the `ScriptTranslator`. More specifically, the implementation of this
+interface which will convert a `Traversal` object (or Gremlin `Bytecode`) into a proper `String` representation that
+is syntactically correct for the implementation language.
 
-See: link:https://issues.apache.org/jira/browse/TINKERPOP-2436[TINKERPOP-2436]
+[source,text]
+----
+gremlin> import org.apache.tinkerpop.gremlin.process.traversal.translator.*
+==>org.apache.tinkerpop.gremlin.structure.*, org.apache.tinkerpop.gremlin.structure.util.*, ...
+gremlin> translator = GroovyTranslator.of('g')
+==>translator[g:gremlin-groovy]
+gremlin> translator.translate(g.V().has("person","name","marko").has("age",gt(20)).where(outE("knows")))
+==>g.V().has("person","name","marko").has("age",P.gt((int) 20)).where(__.outE("knows"))
+gremlin> translator = PythonTranslator.of('g')
+==>translator[g:gremlin-python]
+gremlin> translator.translate(g.V().has("person","name","marko").has("age",gt(20)).where(outE("knows")))
+==>g.V().has('person','name','marko').has('age',P.gt(20)).where(__.outE('knows'))
+----
+
+Some Gremlin users may already be aware of the implementations for Groovy and Python from previous versions. These
+classes have largely been used for testing purposes, but users have found helpful use cases for them and they have
+now been promoted to `gremlin-core` from their original locations. The old versions in `gremlin-groovy` and
+`gremlin-python` have been deprecated. There have been some improvements to the `GroovyTranslator` such that the
+Gremlin generated will not match character for character with the deprecated version. There may also be some potential
+for the newer version in 3.4.9 to generate scripts that will not work in earlier versions. It is therefore best to
+use 3.4.9 translators within environments where 3.4.9 is uniformly supported. If older versions are in place, it may
+be better to continue use of the deprecated versions.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2461[TINKERPOP-2461]
+
+=== withStrategies() Groovy Syntax
+
+The `withStrategies()` configuration step accepts a variable number of `TraversalStrategy` instances. In Java, those
+instances are typically constructed with `instance()` if it is a singleton or by way of a builder pattern which
+provides a fluent, type safe method to create the object. For Groovy, which is highly applicable to those who use
+Gremlin scripts in their applications or work a lot within tools similar to the Gremlin Cosnole, the builder syntax
+can work but doesn't really match the nature of the Groovy language. Using a strategy in this script context would
+look something like:
+
+[source,groovy]
+----
+g.withStrategies(ReadOnlyStrategy.instance(),
+                 SubgraphStrategy.build().vertexProperties(hasNot('endTime')).create())
+----
+
+While this method will still work, it is now possible to use a more succinct syntax for Groovy scripts:
+
+[source,groovy]
+----
+g.withStrategies(ReadOnlyStrategy,
+                 new SubgraphStrategy(vertexProperties: __.hasNot('endTime')))
+----
+
+The rules are straightforward. If a strategy can be instantiated with `instance()` as a singleton then use just the
+class name as a shortcut. Interestingly, many users try this syntax when they first get started and obviously fail.
+With the syntax present, they will have one less error to contend with in their early days of Gremlin. For strategies
+that take configurations, these strategies will use named arguments in the constructor where the names match the
+expected builder methods. This named argument syntax is common to Groovy and not something special to Gremlin - it is
+just now exposed for this purpose.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2466[TINKERPOP-2466]
 
 === withEmbedded()
 
@@ -112,6 +165,16 @@ See: link:https://issues.apache.org/jira/browse/TINKERPOP-2296[TINKERPOP-2296],
 link:https://issues.apache.org/jira/browse/TINKERPOP-2420[TINKERPOP-2420],
 link:https://issues.apache.org/jira/browse/TINKERPOP-2421[TINKERPOP-2421]
 
+=== GraphManager Extension
+
+The `org.apache.tinkerpop.gremlin.server.util.CheckedGraphManager` can be used instead of
+`org.apache.tinkerpop.gremlin.server.util.DefaultGraphManager` (in gremlin-server.yml  to ensures that Gremlin Server
+fails to start if all graphs fails. This configuration option can be useful for a number of different situations (e.g.
+use `CheckedGraphManager` on a Kubernetes cluster to ensure that a pod will be restarted when it cannot properly handle
+requests.) As a final note, `DefaultGraphManager` is no longer `final` and thus can be extended.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2436[TINKERPOP-2436]
+
 === Upgrading for Providers
 
 ==== Graph System Providers
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
index 8cdd84d..c2efdca 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/Translator.java
@@ -67,6 +67,13 @@ public interface Translator<S, T> {
          * representations in their target language.
          */
         public interface TypeTranslator extends BiFunction<String, Object, Object> { }
+
+        /**
+         * Translates a {@link Traversal} into a script form.
+         */
+        public default String translate(final Traversal<?,?> t) {
+            return translate(t.asAdmin().getBytecode());
+        }
     }
 
     /**


[tinkerpop] 02/04: TINKERPOP-2461 Aligned CoreImports with GroovyTranslator

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2461
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit c666e0b181b848f0263c18a6537900eb47aba2b2
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Nov 5 14:03:26 2020 -0500

    TINKERPOP-2461 Aligned CoreImports with GroovyTranslator
    
    This change only applied to the translator in gremlin-core. If folks want the old style they can use the deprecated one for now. The new style is more succinct and fits with the imports.
---
 CHANGELOG.asciidoc                                 |  2 +
 .../tinkerpop/gremlin/jsr223/CoreImports.java      | 13 ++++
 .../traversal/translator/GroovyTranslator.java     | 73 +++++++++++++---------
 .../traversal/translator/GroovyTranslatorTest.java | 28 ++++-----
 .../gremlin/groovy/loaders/StrategyLoader.groovy   |  5 ++
 5 files changed, 78 insertions(+), 43 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index f50c2e4..f41da2b 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,8 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Modified the text of `profile()` output to hide step instances injected for purpose of collecting metrics.
 * Bumped to Jackson 2.11.x.
 * Bumped Netty 4.1.52.
+* Provided a more concise syntax for constructing strategies in Groovy.
+* Aligned `CoreImports` with `GroovyTranslator` to generate more succinct syntax.
 * Moved `Translator` instances to `gremlin-core`.
 * Added `CheckedGraphManager` to prevent Gremlin Server from starting if there are no graphs configured.
 * Fixed bug in bytecode `Bindings` where calling `of()` prior to calling a child traversal in the same parent would cause the initial binding to be lost.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
index cc7881c..1863c2a 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/CoreImports.java
@@ -136,6 +136,10 @@ import org.apache.tinkerpop.gremlin.structure.io.gryo.GryoWriter;
 import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
 import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceEdge;
+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.Gremlin;
 import org.apache.tinkerpop.gremlin.util.TimeUtil;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
@@ -166,6 +170,7 @@ public final class CoreImports {
         // CLASSES //
         /////////////
 
+        // structure
         CLASS_IMPORTS.add(Edge.class);
         CLASS_IMPORTS.add(Element.class);
         CLASS_IMPORTS.add(Graph.class);
@@ -175,6 +180,11 @@ public final class CoreImports {
         CLASS_IMPORTS.add(VertexProperty.class);
         CLASS_IMPORTS.add(GraphFactory.class);
         CLASS_IMPORTS.add(ElementHelper.class);
+        CLASS_IMPORTS.add(ReferenceEdge.class);
+        CLASS_IMPORTS.add(ReferenceProperty.class);
+        CLASS_IMPORTS.add(ReferenceVertex.class);
+        CLASS_IMPORTS.add(ReferenceVertexProperty.class);
+        
         // tokens
         CLASS_IMPORTS.add(SackFunctions.class);
         CLASS_IMPORTS.add(SackFunctions.Barrier.class);
@@ -298,6 +308,9 @@ public final class CoreImports {
         CLASS_IMPORTS.add(IteratorUtils.class);
         CLASS_IMPORTS.add(TimeUtil.class);
         CLASS_IMPORTS.add(Lambda.class);
+        CLASS_IMPORTS.add(java.util.Date.class);
+        CLASS_IMPORTS.add(java.sql.Timestamp.class);
+        CLASS_IMPORTS.add(java.util.UUID.class);
 
         /////////////
         // METHODS //
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
index 1945e82..6e8dc48 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslator.java
@@ -20,6 +20,7 @@ package org.apache.tinkerpop.gremlin.process.traversal.translator;
 
 import org.apache.commons.configuration.ConfigurationConverter;
 import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.tinkerpop.gremlin.jsr223.CoreImports;
 import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
 import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions;
@@ -33,7 +34,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategy
 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.Element;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -51,6 +51,7 @@ import java.util.UUID;
 import java.util.function.BinaryOperator;
 import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
 
 /**
  * Converts bytecode to a Groovy string of Gremlin.
@@ -68,11 +69,11 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
         this.typeTranslator = typeTranslator;
     }
 
-    public static final GroovyTranslator of(final String traversalSource) {
+    public static GroovyTranslator of(final String traversalSource) {
         return of(traversalSource, null);
     }
 
-    public static final GroovyTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
+    public static GroovyTranslator of(final String traversalSource, final TypeTranslator typeTranslator) {
         return new GroovyTranslator(traversalSource,
                 Optional.ofNullable(typeTranslator).orElseGet(DefaultTypeTranslator::new));
     }
@@ -158,13 +159,13 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
             else if (object instanceof Integer)
                 return "(int) " + object;
             else if (object instanceof Class)
-                return ((Class) object).getCanonicalName();
+                return convertClassToString((Class<?>) object);
             else if (object instanceof Timestamp)
-                return "new java.sql.Timestamp(" + ((Timestamp) object).getTime() + ")";
+                return "new Timestamp(" + ((Timestamp) object).getTime() + ")";
             else if (object instanceof Date)
-                return "new java.util.Date(" + ((Date) object).getTime() + ")";
+                return "new Date(" + ((Date) object).getTime() + ")";
             else if (object instanceof UUID)
-                return "java.util.UUID.fromString('" + object.toString() + "')";
+                return "UUID.fromString('" + object.toString() + "')";
             else if (object instanceof P)
                 return convertPToString((P) object, new StringBuilder()).toString();
             else if (object instanceof SackFunctions.Barrier)
@@ -175,40 +176,36 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
                 return "TraversalOptionParent.Pick." + object.toString();
             else if (object instanceof Enum)
                 return ((Enum) object).getDeclaringClass().getSimpleName() + "." + object.toString();
-            else if (object instanceof Element) {
-                if (object instanceof Vertex) {
-                    final Vertex vertex = (Vertex) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
-                            convertToString(vertex.id()) + "," +
-                            convertToString(vertex.label()) + ", Collections.emptyMap())";
-                } else if (object instanceof Edge) {
+            else if (object instanceof Vertex) {
+                final Vertex vertex = (Vertex) object;
+                return "new ReferenceVertex(" +
+                        convertToString(vertex.id()) + "," +
+                        convertToString(vertex.label()) + ")";
+            } else if (object instanceof Edge) {
                     final Edge edge = (Edge) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
+                    return "new ReferenceEdge(" +
                             convertToString(edge.id()) + "," +
                             convertToString(edge.label()) + "," +
-                            "Collections.emptyMap()," +
-                            convertToString(edge.outVertex().id()) + "," +
-                            convertToString(edge.outVertex().label()) + "," +
-                            convertToString(edge.inVertex().id()) + "," +
-                            convertToString(edge.inVertex().label()) + ")";
-                } else {// VertexProperty
-                    final VertexProperty vertexProperty = (VertexProperty) object;
-                    return "new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty(" +
+                            "new ReferenceVertex(" + convertToString(edge.inVertex().id()) + "," +
+                            convertToString(edge.inVertex().label()) + ")," +
+                            "new ReferenceVertex(" + convertToString(edge.outVertex().id()) + "," +
+                            convertToString(edge.outVertex().label()) + "))";
+            } else if (object instanceof VertexProperty) {
+                    final VertexProperty<?> vertexProperty = (VertexProperty<?>) object;
+                    return "new ReferenceVertexProperty(" +
                             convertToString(vertexProperty.id()) + "," +
                             convertToString(vertexProperty.label()) + "," +
-                            convertToString(vertexProperty.value()) + "," +
-                            "Collections.emptyMap()," +
-                            convertToString(vertexProperty.element()) + ")";
-                }
+                            convertToString(vertexProperty.value()) + ")";
             } else if (object instanceof Lambda) {
                 final String lambdaString = ((Lambda) object).getLambdaScript().trim();
                 return lambdaString.startsWith("{") ? lambdaString : "{" + lambdaString + "}";
             } else if (object instanceof TraversalStrategyProxy) {
                 final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object;
+                final String className = convertClassToString(proxy.getStrategyClass());
                 if (proxy.getConfiguration().isEmpty())
-                    return proxy.getStrategyClass().getCanonicalName() + ".instance()";
+                    return className;
                 else
-                    return proxy.getStrategyClass().getCanonicalName() + ".create(new org.apache.commons.configuration.MapConfiguration(" + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + "))";
+                    return String.format("new %s(%s)", className, convertMapToArguments(ConfigurationConverter.getMap(proxy.getConfiguration())));
             } else if (object instanceof TraversalStrategy) {
                 return convertToString(new TraversalStrategyProxy(((TraversalStrategy) object)));
             } else
@@ -275,6 +272,24 @@ public final class GroovyTranslator implements Translator.ScriptTranslator {
             current.append("TextP.").append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")");
             return current;
         }
+
+        /**
+         * Gets the string representation of a class with the default implementation simply checking to see if the
+         * {@code Class} is in {@link CoreImports} or not. If it is present that means it can be referenced using the
+         * simple name otherwise it uses the canonical name.
+         * <p/>
+         * Those building custom {@link ScriptTranslator} instances might override this if they have other classes
+         * that are not in {@link CoreImports} by default.
+         */
+        protected String convertClassToString(final Class<?> clazz) {
+            return CoreImports.getClassImports().contains(clazz) ? clazz.getSimpleName() : clazz.getCanonicalName();
+        }
+
+        private String convertMapToArguments(final Map<Object,Object> map) {
+            return map.entrySet().stream().map(entry ->
+                String.format("%s: %s", entry.getKey().toString(), convertToString(entry.getValue()))).
+                    collect(Collectors.joining(", "));
+        }
     }
 }
 
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
index b370d73..2575b3a 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
@@ -63,7 +63,7 @@ public class GroovyTranslatorTest {
 
     @Test
     public void shouldTranslateStrategies() throws Exception {
-        assertEquals("g.withStrategies(org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy.instance(),org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy.create(new org.apache.commons.configuration.MapConfiguration([(\"checkAdjacentVertices\"):(false),(\"vertices\"):(__.hasLabel(\"person\"))]))).V().has(\"name\")",
+        assertEquals("g.withStrategies(ReadOnlyStrategy,new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.hasLabel(\"person\"))).V().has(\"name\")",
                 translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
                         SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
                         V().has("name").asAdmin().getBytecode()));
@@ -133,7 +133,7 @@ public class GroovyTranslatorTest {
         final Calendar c = Calendar.getInstance();
         c.set(1975, Calendar.SEPTEMBER, 7);
         final Date d = c.getTime();
-        assertTranslation(String.format("new java.util.Date(%s)", d.getTime()), d);
+        assertTranslation(String.format("new Date(%s)", d.getTime()), d);
     }
 
     @Test
@@ -141,13 +141,13 @@ public class GroovyTranslatorTest {
         final Calendar c = Calendar.getInstance();
         c.set(1975, Calendar.SEPTEMBER, 7);
         final Timestamp t = new Timestamp(c.getTime().getTime());
-        assertTranslation(String.format("new java.sql.Timestamp(%s)", t.getTime()), t);
+        assertTranslation(String.format("new Timestamp(%s)", t.getTime()), t);
     }
 
     @Test
     public void shouldTranslateUuid() {
         final UUID uuid = UUID.fromString("ffffffff-fd49-1e4b-0000-00000d4b8a1d");
-        assertTranslation(String.format("java.util.UUID.fromString('%s')", uuid), uuid);
+        assertTranslation(String.format("UUID.fromString('%s')", uuid), uuid);
     }
 
     @Test
@@ -218,18 +218,18 @@ public class GroovyTranslatorTest {
         final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
                 .create();
         final String script1 = translator.translate(g.inject(vertex1).asAdmin().getBytecode());
-        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+        assertEquals("g.inject(new ReferenceVertex(" +
                         "\"customer:10:foo bar \\$100#90\"," +
-                        "\"customer\", Collections.emptyMap()))",
+                        "\"customer\"))",
                 script1);
 
         final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
         final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
                 .create();
         final String script2 = translator.translate(g.inject(vertex2).asAdmin().getBytecode());
-        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(" +
+        assertEquals("g.inject(new ReferenceVertex(" +
                         "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
-                        "\"user\", Collections.emptyMap()))",
+                        "\"user\"))",
                 script2);
 
         final Object id3 = "knows:30:foo\u0020bar\u0020\u0024100:\\u0020\\u0024500#70";
@@ -238,19 +238,19 @@ public class GroovyTranslatorTest {
                 .setInV((DetachedVertex) vertex2)
                 .create();
         final String script3 = translator.translate(g.inject(edge).asAdmin().getBytecode());
-        assertEquals("g.inject(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge(" +
+        assertEquals("g.inject(new ReferenceEdge(" +
                         "\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
-                        "\"knows\",Collections.emptyMap()," +
-                        "\"customer:10:foo bar \\$100#90\",\"customer\"," +
-                        "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))",
+                        "\"knows\"," +
+                        "new ReferenceVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\")," +
+                        "new ReferenceVertex(\"customer:10:foo bar \\$100#90\",\"customer\")))",
                 script3);
 
         final String script4 = translator.translate(
                 g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
                         .asAdmin().getBytecode());
         assertEquals("g.addE(\"knows\")" +
-                        ".from(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"customer:10:foo bar \\$100#90\",\"customer\", Collections.emptyMap()))" +
-                        ".to(new org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\", Collections.emptyMap()))" +
+                        ".from(new ReferenceVertex(\"customer:10:foo bar \\$100#90\",\"customer\"))" +
+                        ".to(new ReferenceVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))" +
                         ".property(\"when\",\"2018/09/21\")",
                 script4);
     }
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
index 5396737..b9651fd 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.groovy.loaders
 
 import org.apache.commons.configuration.MapConfiguration
+import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy
@@ -52,11 +53,13 @@ class StrategyLoader {
         // SackStrategy.metaClass.constructor << { Map conf -> SackStrategy.create(new MapConfiguration(conf)) }
         // # SideEffectStrategy is internal
         SubgraphStrategy.metaClass.constructor << { Map conf -> SubgraphStrategy.create(new MapConfiguration(conf)) }
+        VertexProgramStrategy.metaClass.constructor << { Map conf -> VertexProgramStrategy.create(new MapConfiguration(conf)) }
 
         // finalization
         MatchAlgorithmStrategy.metaClass.constructor << { Map conf -> MatchAlgorithmStrategy.create(new MapConfiguration(conf)) }
         // # ProfileStrategy is singleton/internal
         // # ReferenceElementStrategy is singleton/internal
+        // # ComputerFinalizationStrategy is singleton/internal
 
         // optimization
         // # AdjacentToIncidentStrategy is singleton/internal
@@ -72,6 +75,8 @@ class StrategyLoader {
         // # PathProcessorStrategy is singleton/internal
         // # PathRetractionStrategy is singleton/internal
         // # RepeatUnrollStrategy is singleton/internal
+        // # GraphFilterStrategy is singleton/internal
+        // # MessagePassingReductionStrategy is singleton/internal
 
         // verification
         // # ComputerVerificationStrategy is singleton/internal


[tinkerpop] 04/04: TINKERPOP-2461 Added reference documentation for Translator

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2461
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 127821e36321ccf2544f62683abd4c7360051ede
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Fri Nov 6 11:59:15 2020 -0500

    TINKERPOP-2461 Added reference documentation for Translator
---
 docs/src/reference/gremlin-variants.asciidoc       |   4 +-
 docs/src/reference/the-traversal.asciidoc          |  63 +++++++++++++++++++++
 docs/static/images/gremlin-translator.png          | Bin 0 -> 998775 bytes
 .../traversal/translator/GroovyTranslatorTest.java |  30 +++++-----
 4 files changed, 80 insertions(+), 17 deletions(-)

diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index b3c13cb..4cdc783 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -626,8 +626,8 @@ Gremlin-Java constructs. Moreover, given its scripting nature, Gremlin-Groovy se
 
 [source,groovy]
 ----
-compile group: 'org.apache.tinkerpop', name: 'gremlin-core', version: '3.3.4'
-compile group: 'org.apache.tinkerpop', name: 'gremlin-driver', version: '3.3.4'
+compile group: 'org.apache.tinkerpop', name: 'gremlin-core', version: 'x.y.z'
+compile group: 'org.apache.tinkerpop', name: 'gremlin-driver', version: 'x.y.z'
 ----
 
 [[gremlin-groovy-differences]]
diff --git a/docs/src/reference/the-traversal.asciidoc b/docs/src/reference/the-traversal.asciidoc
index 7fce8f1..a192993 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -4176,3 +4176,66 @@ social.persons("marko").youngestFriendsAge()
 
 Learn more about how to implement these DSLs in the <<gremlin-drivers-variants,Gremlin Language Variants>> section
 specific to the programming language of interest.
+
+[[translators]]
+== Translators
+
+image::gremlin-translator.png[width=1024]
+
+There are times when is helpful to translate Gremlin from one programming language to another. Perhaps a large Gremlin
+example is found on StackOverflow written in Java, but the programming language the developer has chosen is Python.
+Fortunately, TinkerPop has developed `Translator` infrastructure that will convert Gremlin from one programming
+language syntax to another.
+
+The functionality relevant to most users is actually a sub-function of `Translator` infrastructure and is more
+specifically a `ScriptTranslator` which takes Gremlin `Bytecode` of a traversal and generates a `String` representation
+of that `Bytecode` in the programming language syntax that the `ScriptTranslator` instance supports. The translation
+therefore allows Gremlin to be converted from the host programming language of the `Translator` to another.
+
+The following translators are available:
+
+[width="100%",cols="<,^,^,^,^,^",options="header"]
+|=========================================================
+| |Java |Groovy |Javascript |.NET |Python
+|*Java* |- |X | | |X
+|*Groovy* | |- | | |X
+|*Javascript* | |X |- | |
+|*.NET* | | | |- |
+|*Python*  | | | | |-
+|=========================================================
+
+Each programming language has its own API for translation, but the pattern is quite similar from one to the next:
+
+WARN: While `Translator` implementations have been around for some time, they are still in their early stages from
+an interface perspective. API changes may occur in the near future.
+
+[source,java,tab]
+----
+// gremlin-core module
+import org.apache.tinkerpop.gremlin.process.traversal.translator.*;
+GraphTraversalSource g = ...;
+Traversal<Vertex,Integer> t = g.V().has("person","name","marko").
+                                where(in("knows")).
+                                values("age").
+                                map(Lambda.Function("it.get() + 1");
+
+Translator.ScriptTranslator groovyTranslator = GroovyTranslator.of("g");
+System.out.println(groovyTranslator.translate(t);
+// OUTPUT: g.V().has("person","name","marko").where(__.in("knows")).values("age").map({it.get() + 1})
+
+Translator.ScriptTranslator pythonTranslator = PythonTranslator.of("g");
+// OUTPUT: g.V().has('person','name','marko').where(__.in_('knows')).age.map(lambda it.get() + 1)
+----
+[source,javascript]
+----
+const g = ...;
+const t = g.V().has("person","name","marko").
+            where(in_("knows")).
+            values("age");
+
+// groovy
+const translator = new gremlin.process.Translator('g');
+console.log(translator.translate(t));
+// OUTPUT: g.V().has('person','name','marko').where(__.in('knows')).values('age')
+----
+
diff --git a/docs/static/images/gremlin-translator.png b/docs/static/images/gremlin-translator.png
new file mode 100644
index 0000000..ce42425
Binary files /dev/null and b/docs/static/images/gremlin-translator.png differ
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
index 2575b3a..8455293 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/translator/GroovyTranslatorTest.java
@@ -66,25 +66,25 @@ public class GroovyTranslatorTest {
         assertEquals("g.withStrategies(ReadOnlyStrategy,new SubgraphStrategy(checkAdjacentVertices: false, vertices: __.hasLabel(\"person\"))).V().has(\"name\")",
                 translator.translate(g.withStrategies(ReadOnlyStrategy.instance(),
                         SubgraphStrategy.build().checkAdjacentVertices(false).vertices(hasLabel("person")).create()).
-                        V().has("name").asAdmin().getBytecode()));
+                        V().has("name")));
     }
 
     @Test
     public void shouldTranslateConfusingSacks() {
         final Traversal<Vertex,Double> tConstantUnary = g.withSack(1.0, Lambda.unaryOperator("it + 1")).V().sack();
-        final String scriptConstantUnary = translator.translate(tConstantUnary.asAdmin().getBytecode());
+        final String scriptConstantUnary = translator.translate(tConstantUnary);
         assertEquals("g.withSack(1.0d, (java.util.function.UnaryOperator) {it + 1}).V().sack()", scriptConstantUnary);
 
         final Traversal<Vertex,Double> tSupplierUnary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>unaryOperator("it + 1")).V().sack();
-        final String scriptSupplierUnary = translator.translate(tSupplierUnary.asAdmin().getBytecode());
+        final String scriptSupplierUnary = translator.translate(tSupplierUnary);
         assertEquals("g.withSack((java.util.function.Supplier) {1.0d}, (java.util.function.UnaryOperator) {it + 1}).V().sack()", scriptSupplierUnary);
 
         final Traversal<Vertex,Double> tConstantBinary = g.withSack(1.0, Lambda.binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptConstantBinary = translator.translate(tConstantBinary.asAdmin().getBytecode());
+        final String scriptConstantBinary = translator.translate(tConstantBinary);
         assertEquals("g.withSack(1.0d, (java.util.function.BinaryOperator) {x,y -> x + y + 1}).V().sack()", scriptConstantBinary);
 
         final Traversal<Vertex,Double> tSupplierBinary = g.withSack(Lambda.supplier("1.0d"), Lambda.<Double>binaryOperator("x,y -> x + y + 1")).V().sack();
-        final String scriptSupplierBinary = translator.translate(tSupplierBinary.asAdmin().getBytecode());
+        final String scriptSupplierBinary = translator.translate(tSupplierBinary);
         assertEquals("g.withSack((java.util.function.Supplier) {1.0d}, (java.util.function.BinaryOperator) {x,y -> x + y + 1}).V().sack()", scriptSupplierBinary);
     }
 
@@ -117,14 +117,14 @@ public class GroovyTranslatorTest {
         final String script = translator.translate(g.V().id().is(new LinkedHashMap<Object,Object>() {{
             put(3, "32");
             put(Arrays.asList(1, 2, 3.1d), 4);
-        }}).asAdmin().getBytecode());
+        }}));
         assertEquals("g.V().id().is([((int) 3):(\"32\"),([(int) 1, (int) 2, 3.1d]):((int) 4)])", script);
     }
 
     @Test
     public void shouldTranslateEmptyMaps() {
         final Function identity = new Lambda.OneArgLambda("it.get()", "gremlin-groovy");
-        final String script = translator.translate(g.inject(Collections.emptyMap()).map(identity).asAdmin().getBytecode());
+        final String script = translator.translate(g.inject(Collections.emptyMap()).map(identity));
         assertEquals("g.inject([]).map({it.get()})", script);
     }
 
@@ -181,12 +181,12 @@ public class GroovyTranslatorTest {
 
         // without type translation we get uglinesss
         final String scriptBad = translator.
-                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+                translate(g.inject(notSillyEnough));
         assertEquals(String.format("g.inject(%s)", "not silly enough:100"), scriptBad);
 
         // with type translation we get valid gremlin
         final String scriptGood = GroovyTranslator.of("g", new SillyClassTranslator()).
-                translate(g.inject(notSillyEnough).asAdmin().getBytecode());
+                translate(g.inject(notSillyEnough));
         assertEquals(String.format("g.inject(org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslatorTest.SillyClass.from('%s', (int) %s))", notSillyEnough.getX(), notSillyEnough.getY()), scriptGood);
     }
 
@@ -202,7 +202,7 @@ public class GroovyTranslatorTest {
                 .property("name", "Foo\u0020Bar")
                 .property("age", 25)
                 .property("special", "`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?")
-                .asAdmin().getBytecode());
+                );
 
         assertEquals("g.addV(\"customer\")" +
                         ".property(\"customer_id\",501L)" +
@@ -217,7 +217,7 @@ public class GroovyTranslatorTest {
         final Object id1 = "customer:10:foo\u0020bar\u0020\u0024100#90"; // customer:10:foo bar $100#90
         final Vertex vertex1 = DetachedVertex.build().setLabel("customer").setId(id1)
                 .create();
-        final String script1 = translator.translate(g.inject(vertex1).asAdmin().getBytecode());
+        final String script1 = translator.translate(g.inject(vertex1));
         assertEquals("g.inject(new ReferenceVertex(" +
                         "\"customer:10:foo bar \\$100#90\"," +
                         "\"customer\"))",
@@ -226,7 +226,7 @@ public class GroovyTranslatorTest {
         final Object id2 = "user:20:foo\\u0020bar\\u005c\\u0022mr\\u005c\\u0022\\u00241000#50"; // user:20:foo\u0020bar\u005c\u0022mr\u005c\u0022\u00241000#50
         final Vertex vertex2 = DetachedVertex.build().setLabel("user").setId(id2)
                 .create();
-        final String script2 = translator.translate(g.inject(vertex2).asAdmin().getBytecode());
+        final String script2 = translator.translate(g.inject(vertex2));
         assertEquals("g.inject(new ReferenceVertex(" +
                         "\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\"," +
                         "\"user\"))",
@@ -237,7 +237,7 @@ public class GroovyTranslatorTest {
                 .setOutV((DetachedVertex) vertex1)
                 .setInV((DetachedVertex) vertex2)
                 .create();
-        final String script3 = translator.translate(g.inject(edge).asAdmin().getBytecode());
+        final String script3 = translator.translate(g.inject(edge));
         assertEquals("g.inject(new ReferenceEdge(" +
                         "\"knows:30:foo bar \\$100:\\\\u0020\\\\u0024500#70\"," +
                         "\"knows\"," +
@@ -247,7 +247,7 @@ public class GroovyTranslatorTest {
 
         final String script4 = translator.translate(
                 g.addE("knows").from(vertex1).to(vertex2).property("when", "2018/09/21")
-                        .asAdmin().getBytecode());
+                        );
         assertEquals("g.addE(\"knows\")" +
                         ".from(new ReferenceVertex(\"customer:10:foo bar \\$100#90\",\"customer\"))" +
                         ".to(new ReferenceVertex(\"user:20:foo\\\\u0020bar\\\\u005c\\\\u0022mr\\\\u005c\\\\u0022\\\\u00241000#50\",\"user\"))" +
@@ -256,7 +256,7 @@ public class GroovyTranslatorTest {
     }
 
     private void assertTranslation(final String expectedTranslation, final Object... objs) {
-        final String script = translator.translate(g.inject(objs).asAdmin().getBytecode());
+        final String script = translator.translate(g.inject(objs));
         assertEquals(String.format("g.inject(%s)", expectedTranslation), script);
     }
 


[tinkerpop] 01/04: TINKERPOP-2466 Provided more succinct syntax for withStrategies()

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2461
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 19411e212d5d6e9a99319f821f0f0ee141f8bad9
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Thu Nov 5 08:11:25 2020 -0500

    TINKERPOP-2466 Provided more succinct syntax for withStrategies()
    
    Allowed scripts a more succinct and Groovy style for strategy construction when using withStrategies().
---
 .../strategy/decoration/EventStrategy.java         | 12 +--
 .../strategy/decoration/SackStrategy.java          |  4 +
 .../gremlin/groovy/loaders/GremlinLoader.groovy    |  4 +-
 .../gremlin/groovy/loaders/ObjectLoader.groovy     |  2 +-
 .../gremlin/groovy/loaders/StepLoader.groovy       | 22 +++++-
 .../gremlin/groovy/loaders/StrategyLoader.groovy   | 85 ++++++++++++++++++++++
 .../gremlin/groovy/loaders/SugarLoader.groovy      |  2 +-
 .../jsr223/GremlinGroovyScriptEngineTest.java      | 36 +++++++++
 8 files changed, 153 insertions(+), 14 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
index 2061e7f..c442e52 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/EventStrategy.java
@@ -26,19 +26,10 @@ import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.EventCallb
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.event.MutationListener;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
-import org.apache.tinkerpop.gremlin.structure.Edge;
-import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
-import org.apache.tinkerpop.gremlin.structure.Property;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
-import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.structure.VertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedFactory;
-import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedProperty;
-import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertexProperty;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
-import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceProperty;
-import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceVertexProperty;
 
 import java.io.Serializable;
 import java.util.ArrayDeque;
@@ -51,7 +42,8 @@ import java.util.List;
  * A strategy that raises events when {@link Mutating} steps are encountered and successfully executed.
  * <p/>
  * Note that this implementation requires a {@link Graph} on the {@link Traversal} instance.  If that is not present
- * an {@code IllegalStateException} will be thrown.
+ * an {@code IllegalStateException} will be thrown. Finally, this strategy is meant for use on the JVM only and has
+ * no analogous implementation in other Gremlin Language Variants.
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
index 0598d17..7124b61 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/decoration/SackStrategy.java
@@ -20,6 +20,7 @@
 package org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -29,6 +30,9 @@ import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
 
 /**
+ * The {@code SackStrategy} is used internal to the {@code withSack()} steps of {@link TraversalSource} and is not
+ * typically constructed directly.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
 public final class SackStrategy extends AbstractTraversalStrategy<TraversalStrategy.DecorationStrategy> implements TraversalStrategy.DecorationStrategy {
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/GremlinLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/GremlinLoader.groovy
index 758768e..b2e50d9 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/GremlinLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/GremlinLoader.groovy
@@ -17,14 +17,16 @@
  * under the License.
  */
 package org.apache.tinkerpop.gremlin.groovy.loaders
+
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 class GremlinLoader {
 
-    public static void load() {
+    static void load() {
         ObjectLoader.load()
         StepLoader.load()
+        StrategyLoader.load()
     }
 }
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/ObjectLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/ObjectLoader.groovy
index b7f0ec2..9285d05 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/ObjectLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/ObjectLoader.groovy
@@ -23,7 +23,7 @@ package org.apache.tinkerpop.gremlin.groovy.loaders
 
 class ObjectLoader {
 
-    public static void load() {
+    static void load() {
 
         Map.metaClass.getAt = { final IntRange range ->
             final int size = delegate.size();
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
index b1cd97f..d04a2c4 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StepLoader.groovy
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.groovy.loaders
 
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal
 
 import java.util.function.BinaryOperator
@@ -31,7 +32,7 @@ import java.util.function.UnaryOperator
  */
 class StepLoader {
 
-    public static void load() {
+    static void load() {
 
         GraphTraversal.metaClass.by = { final Closure closure ->
             return ((GraphTraversal) delegate).by(1 == closure.getMaximumNumberOfParameters() ? closure as Function : closure as Comparator);
@@ -63,5 +64,24 @@ class StepLoader {
             final Closure closure, final Closure splitOperator, final Closure mergeOperator ->
                 return ((TraversalSource) delegate).withSack(closure as Supplier, splitOperator as UnaryOperator, mergeOperator as BinaryOperator);
         }
+
+        /**
+         * Allows for a mix of arguments which may be either {@code TraversalStrategy} object or a
+         * {@code Class<TraversalStrategy>}. If the latter, then the class must be able to be instantiated by the
+         * common convention of {@code instance()}.
+         */
+        TraversalSource.metaClass.withStrategies = { Object... traversalStrategyClassOrInstances ->
+            def instances = traversalStrategyClassOrInstances.collect {
+                if (it instanceof TraversalStrategy) {
+                    return it
+                } else if (it instanceof Class<?>) {
+                    def inst = it.metaClass.respondsTo(it, "instance") ? it."instance"() : null
+                    if (null == inst) throw new IllegalArgumentException("${it.name} missing a static 'instance()' method")
+                    return inst
+                }
+            }
+
+            return ((TraversalSource) delegate).withStrategies(*instances)
+        }
     }
 }
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
new file mode 100644
index 0000000..5396737
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/StrategyLoader.groovy
@@ -0,0 +1,85 @@
+/*
+ * 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.groovy.loaders
+
+import org.apache.commons.configuration.MapConfiguration
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReservedKeysVerificationStrategy
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+class StrategyLoader {
+
+    static void load() {
+        // EventStrategy/SackStrategy are pretty much the oddballs here along with a few pure "internal" strategies
+        // which don't have create(Configuration). We don't support either EventStrategy or SackStrategy in non-JVM
+        // variants because of their style of usage (JVM specific class structures and lambdas respectively). this
+        // perhaps points to a shortcoming somewhere in the APIs, though i'm not sure EventStrategy would ever work
+        // properly off the JVM and SackStrategy doesn't need to since it's technically like OptionsStrategy which is
+        // constructed via bytecode translation where the lambdas are readily supported.
+
+        // decoration
+        // # ConnectiveStrategy is singleton
+        ElementIdStrategy.metaClass.constructor << { Map conf -> ElementIdStrategy.create(new MapConfiguration(conf)) }
+        //EventStrategy.metaClass.constructor << { Map conf -> EventStrategy.create(new MapConfiguration(conf)) }
+        HaltedTraverserStrategy.metaClass.constructor << { Map conf -> HaltedTraverserStrategy.create(new MapConfiguration(conf)) }
+        OptionsStrategy.metaClass.constructor << { Map conf -> OptionsStrategy.create(new MapConfiguration(conf)) }
+        PartitionStrategy.metaClass.constructor << { Map conf -> PartitionStrategy.create(new MapConfiguration(conf)) }
+        // # RequirementsStrategy is internal
+        // SackStrategy.metaClass.constructor << { Map conf -> SackStrategy.create(new MapConfiguration(conf)) }
+        // # SideEffectStrategy is internal
+        SubgraphStrategy.metaClass.constructor << { Map conf -> SubgraphStrategy.create(new MapConfiguration(conf)) }
+
+        // finalization
+        MatchAlgorithmStrategy.metaClass.constructor << { Map conf -> MatchAlgorithmStrategy.create(new MapConfiguration(conf)) }
+        // # ProfileStrategy is singleton/internal
+        // # ReferenceElementStrategy is singleton/internal
+
+        // optimization
+        // # AdjacentToIncidentStrategy is singleton/internal
+        // # CountStrategy is singleton/internal
+        // # EarlyLimitStrategy is singleton/internal
+        // # FilterRankingStrategy is singleton/internal
+        // # IdentityRemovalStrategy is singleton/internal
+        // # IncidentToAdjacentStrategy is singleton/internal
+        // # InlineFilterStrategy is singleton/internal
+        // # LazyBarrierStrategy is singleton/internal
+        // # MatchPredicateStrategy is singleton/internal
+        // # OrderLimitStrategy is singleton/internal
+        // # PathProcessorStrategy is singleton/internal
+        // # PathRetractionStrategy is singleton/internal
+        // # RepeatUnrollStrategy is singleton/internal
+
+        // verification
+        // # ComputerVerificationStrategy is singleton/internal
+        EdgeLabelVerificationStrategy.metaClass.constructor << { Map conf -> EdgeLabelVerificationStrategy.create(new MapConfiguration(conf)) }
+        // # LambdaRestrictionStrategy is singleton
+        // # ReadOnlyStrategy is singleton
+        ReservedKeysVerificationStrategy.metaClass.constructor << { Map conf -> ReservedKeysVerificationStrategy.create(new MapConfiguration(conf)) }
+        // # StandardVerificationStrategy is singleton/internal
+    }
+
+}
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/SugarLoader.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/SugarLoader.groovy
index bfc877e..5dd202d 100644
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/SugarLoader.groovy
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/loaders/SugarLoader.groovy
@@ -33,7 +33,7 @@ class SugarLoader {
 
     private static final String NAME = "name";
 
-    public static void load() {
+    static void load() {
 
         GremlinLoader.load();
 
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
index d40dc19..efb6812 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -23,6 +23,13 @@ import groovy.lang.MissingMethodException;
 import groovy.lang.MissingPropertyException;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.filter.HasStep;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.VerificationException;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.apache.tinkerpop.gremlin.util.function.Lambda;
 import org.javatuples.Pair;
 import org.junit.Test;
@@ -38,12 +45,14 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.IntStream;
 
+import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.hasLabel;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
@@ -413,4 +422,31 @@ public class GremlinGroovyScriptEngineTest {
         final Lambda l = (Lambda) engine.eval(" org.apache.tinkerpop.gremlin.util.function.Lambda.function(\"{ it.get() }\")");
         assertEquals("{ it.get() }", l.getLambdaScript());
     }
+
+    @Test
+    public void shouldAllowGroovySyntaxForStrategies() throws Exception {
+        final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+        final GraphTraversalSource g = EmptyGraph.instance().traversal();
+
+        final Bindings b = new SimpleBindings();
+        b.put("g", g);
+
+        Traversal t = (Traversal) engine.eval("g.withStrategies(ReadOnlyStrategy).V()", b);
+        Optional<ReadOnlyStrategy> ro = t.asAdmin().getStrategies().getStrategy(ReadOnlyStrategy.class);
+        assertThat(ro.isPresent(), is(true));
+        assertEquals(ReadOnlyStrategy.instance(), ro.get());
+
+        t = (Traversal) engine.eval("g.withStrategies(new SubgraphStrategy(vertices: __.hasLabel(\"person\"))).V()", b);
+        Optional<SubgraphStrategy> ss = t.asAdmin().getStrategies().getStrategy(SubgraphStrategy.class);
+        assertThat(ss.isPresent(), is(true));
+        assertEquals(HasStep.class, ss.get().getVertexCriterion().asAdmin().getStartStep().getClass());
+
+        t = (Traversal) engine.eval("g.withStrategies(ReadOnlyStrategy, new SubgraphStrategy(vertices: __.hasLabel(\"person\"))).V()", b);
+        ro = t.asAdmin().getStrategies().getStrategy(ReadOnlyStrategy.class);
+        assertThat(ro.isPresent(), is(true));
+        assertEquals(ReadOnlyStrategy.instance(), ro.get());
+        ss = t.asAdmin().getStrategies().getStrategy(SubgraphStrategy.class);
+        assertThat(ss.isPresent(), is(true));
+        assertEquals(HasStep.class, ss.get().getVertexCriterion().asAdmin().getStartStep().getClass());
+    }
 }
\ No newline at end of file