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