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:09 UTC

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

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