You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by co...@apache.org on 2024/10/01 18:08:59 UTC

(tinkerpop) 01/03: WIP update TraversalStrategyProxy to construct custom strategies

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

colegreer pushed a commit to branch customStrategyConstruction
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 1455ccac7c0a087e8a282d77200465d36bac2ab0
Author: Cole-Greer <Co...@improving.com>
AuthorDate: Tue Oct 1 09:20:32 2024 -0700

    WIP update TraversalStrategyProxy to construct custom strategies
---
 .../gremlin/process/traversal/GremlinLang.java     | 17 ++++-
 .../traversal/strategy/TraversalStrategyProxy.java | 29 ++++++--
 .../jsr223/GremlinLangScriptEngineTest.java        | 66 ++++++++++++++++++
 .../strategy/TraversalStrategyProxyTest.java       | 81 ++++++++++++++++++++++
 4 files changed, 185 insertions(+), 8 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
index 1b50dee8c7..daacf02ecd 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GremlinLang.java
@@ -22,6 +22,7 @@ package org.apache.tinkerpop.gremlin.process.traversal;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.text.StringEscapeUtils;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
 import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP;
 import org.apache.tinkerpop.gremlin.process.traversal.util.DefaultTraversal;
@@ -372,13 +373,23 @@ public class GremlinLang implements Cloneable, Serializable {
                 break;
             }
 
-            final Configuration configuration = ((TraversalStrategy) arguments[i]).getConfiguration();
+            Configuration configuration;
+            String strategyName;
+
+            // special handling for TraversalStrategyProxy
+            if (arguments[i] instanceof TraversalStrategyProxy) {
+                configuration = ((TraversalStrategy) arguments[i]).getConfiguration();
+                strategyName = ((TraversalStrategyProxy) arguments[i]).getStrategyName();
+            } else {
+                configuration = ((TraversalStrategy) arguments[i]).getConfiguration();
+                strategyName = arguments[i].getClass().getSimpleName();
+            }
 
             if (configuration.isEmpty()) {
-                sb.append(arguments[i].getClass().getSimpleName());
+                sb.append(strategyName);
             } else {
                 sb.append("new ")
-                        .append(arguments[i].getClass().getSimpleName())
+                        .append(strategyName)
                         .append("(");
 
                 configuration.getKeys().forEachRemaining(key -> {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
index 363fd89b84..5dd39c26b7 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxy.java
@@ -20,13 +20,17 @@
 package org.apache.tinkerpop.gremlin.process.traversal.strategy;
 
 import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.tinkerpop.gremlin.language.grammar.TraversalStrategyVisitor;
 import org.apache.tinkerpop.gremlin.process.traversal.GremlinLang;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.io.Serializable;
+import java.util.Collections;
 
 /**
  * This class is for use with {@link GremlinLang} and for serialization purposes. It is not meant for direct use with
@@ -37,23 +41,38 @@ import java.io.Serializable;
 public final class TraversalStrategyProxy<T extends TraversalStrategy> implements Serializable, TraversalStrategy {
 
     private final Configuration configuration;
-    private final Class<T> strategyClass;
+    private final String strategyName;
 
+    public TraversalStrategyProxy(final String strategyName) {
+        this(strategyName, new MapConfiguration(Collections.EMPTY_MAP));
+    }
+
+    public TraversalStrategyProxy(final String strategyName, final Configuration configuration) {
+        this.configuration = configuration;
+        this.strategyName = strategyName;
+    }
+
+    @Deprecated
     public TraversalStrategyProxy(final T traversalStrategy) {
-        this((Class<T>) traversalStrategy.getClass(), traversalStrategy.getConfiguration());
+        this(traversalStrategy.getClass().getSimpleName(), traversalStrategy.getConfiguration());
     }
 
+    @Deprecated
     public TraversalStrategyProxy(final Class<T> strategyClass, final Configuration configuration) {
-        this.configuration = configuration;
-        this.strategyClass = strategyClass;
+        this(strategyClass.getSimpleName(), configuration);
     }
 
     public Configuration getConfiguration() {
         return this.configuration;
     }
 
+    public String getStrategyName() {
+        return this.strategyName;
+    }
+
+    @Deprecated
     public Class<T> getStrategyClass() {
-        return this.strategyClass;
+        return (Class<T>) TraversalStrategies.GlobalCache.getRegisteredStrategyClass(strategyName).get();
     }
 
     @Override
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
index 9846363030..22dd49659e 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/jsr223/GremlinLangScriptEngineTest.java
@@ -18,8 +18,16 @@
  */
 package org.apache.tinkerpop.gremlin.jsr223;
 
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.MapConfiguration;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxyTest;
 import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
 import org.junit.Test;
 
@@ -27,9 +35,18 @@ import javax.script.Bindings;
 import javax.script.ScriptException;
 import javax.script.SimpleBindings;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 public class GremlinLangScriptEngineTest {
 
@@ -59,4 +76,53 @@ public class GremlinLangScriptEngineTest {
         assertThat(result, instanceOf(Traversal.Admin.class));
         assertEquals(g.V(100, 1000, 10000).asAdmin().getGremlinLang(), ((Traversal.Admin) result).getGremlinLang());
     }
+
+    public static class TestStrategy<S extends TraversalStrategy> extends AbstractTraversalStrategy<S> {
+        private final Configuration configuration;
+
+        private TestStrategy(final Configuration configuration) {
+            this.configuration = configuration;
+        }
+        @Override
+        public void apply(Traversal.Admin traversal) {
+            // Do nothing
+        }
+
+        @Override
+        public Configuration getConfiguration() {
+            return configuration;
+        }
+
+        public static TestStrategy create(Configuration configuration) {
+            return new TestStrategy(configuration);
+        }
+    }
+
+    @Test
+    public void shouldReconstructCustomRegisteredStrategy() throws ScriptException {
+        TraversalStrategies.GlobalCache.registerStrategy(TestStrategy.class);
+
+        GraphTraversal traversal = (GraphTraversal) scriptEngine.eval("g.withStrategies(new TestStrategy(stringKey:\"stringValue\",intKey:1,booleanKey:true)).V()");
+
+        TestStrategy reconstructedStrategy = traversal.asAdmin().getStrategies().getStrategy(TestStrategy.class).get();
+
+        assertNotNull(reconstructedStrategy);
+
+        MapConfiguration expectedConfig = new MapConfiguration(new HashMap<String, Object>() {{
+            put("stringKey", "stringValue");
+            put("intKey", 1);
+            put("booleanKey", true);
+        }});
+
+        Set<String> expectedKeys = new HashSet<>();
+        Set<String> actualKeys = new HashSet<>();
+        expectedConfig.getKeys().forEachRemaining((key) -> expectedKeys.add(key));
+        reconstructedStrategy.getConfiguration().getKeys().forEachRemaining((key) -> actualKeys.add(key));
+
+        assertEquals(expectedKeys, actualKeys);
+
+        expectedKeys.forEach((key) -> {
+            assertEquals(expectedConfig.get(Object.class, key), reconstructedStrategy.getConfiguration().get(Object.class, key));
+        });
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxyTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxyTest.java
new file mode 100644
index 0000000000..cf4a228176
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/TraversalStrategyProxyTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tinkerpop.gremlin.process.traversal.strategy;
+
+import org.apache.commons.configuration2.MapConfiguration;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+public class TraversalStrategyProxyTest {
+
+    private static class TestStrategy<S extends TraversalStrategy> extends AbstractTraversalStrategy<S> {
+        @Override
+        public void apply(Traversal.Admin traversal) {
+            // Do nothing
+        }
+    }
+
+    @Test
+    public void shouldAddCustomStrategyToGremlinScript() {
+        TraversalStrategyProxy strategyProxy = new TraversalStrategyProxy("TestStrategy");
+        GraphTraversalSource g = EmptyGraph.instance().traversal();
+        GraphTraversal traversal = g.withStrategies(strategyProxy).V();
+        assertEquals("g.withStrategies(TestStrategy).V()", traversal.asAdmin().getGremlinLang().getGremlin());
+    }
+
+    @Test
+    public void shouldAddCustomStrategyWithConfigToGremlinScript() {
+        Map<String, Object> configMap = new LinkedHashMap<>();
+        configMap.put("stringKey", "stringValue");
+        configMap.put("intKey", 1);
+        configMap.put("booleanKey", true);
+        TraversalStrategyProxy strategyProxy = new TraversalStrategyProxy("TestStrategy", new MapConfiguration(configMap));
+
+        GraphTraversalSource g = EmptyGraph.instance().traversal();
+        GraphTraversal traversal = g.withStrategies(strategyProxy).V();
+
+        assertEquals("g.withStrategies(new TestStrategy(stringKey:\"stringValue\",intKey:1,booleanKey:true)).V()", traversal.asAdmin().getGremlinLang().getGremlin());
+    }
+
+    @Test
+    public void gremlinLangShouldReconstructRegisteredCustomStrategyFromScript() {
+        TraversalStrategies.GlobalCache.registerStrategy(TestStrategy.class);
+
+        Map<String, Object> configMap = new LinkedHashMap<>();
+        configMap.put("stringKey", "stringValue");
+        configMap.put("intKey", 1);
+        configMap.put("booleanKey", true);
+        TraversalStrategyProxy strategyProxy = new TraversalStrategyProxy("TestStrategy", new MapConfiguration(configMap));
+
+        GraphTraversalSource g = EmptyGraph.instance().traversal();
+        GraphTraversal traversal = g.withStrategies(strategyProxy).V();
+
+        //GremlinLangScriptEngine
+    }
+
+}