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 2018/05/30 18:07:46 UTC

[19/22] tinkerpop git commit: wip

wip


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

Branch: refs/heads/TINKERPOP-1975
Commit: 99a4b368d7f48dd4cf054dc5c71af71cc7e78b09
Parents: ff6f6d8
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri May 25 16:02:59 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Wed May 30 13:46:14 2018 -0400

----------------------------------------------------------------------
 .../step/util/DefaultStepConfiguration.java     | 158 ++++++++++++++++++
 .../step/util/StepConfigurationProxy.java       |  50 ++++++
 .../step/util/DefaultStepConfigurationTest.java | 167 +++++++++++++++++++
 .../Process/Traversal/IStepConfiguration.cs     |  32 ++++
 4 files changed, 407 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/99a4b368/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfiguration.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfiguration.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfiguration.java
new file mode 100644
index 0000000..b75358f
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfiguration.java
@@ -0,0 +1,158 @@
+/*
+ * 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.step.util;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.lang.reflect.MethodUtils;
+import org.apache.tinkerpop.gremlin.process.remote.traversal.strategy.decoration.RemoteStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * A basic {@link StepConfiguration} implementation that uses reflection to set methods on the step to which the
+ * configuration will be applied. While use of reflection isn't quite as nice as direct application of configuration
+ * options to a step, this implementation is serialization ready and thus requires no additional work from the
+ * developer to get a step option ready for usage. If using this implementation, it is of extreme importance that
+ * the developer implement solid test coverage to ensure that reflection calls will work at runtime as compilation
+ * errors will not be raised under this approach.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class DefaultStepConfiguration implements StepConfiguration<Step> {
+
+    private final Map<String, List<Object>> conf;
+    private final Class<? extends Step> expects;
+
+    /**
+     * Creates a new {@code DefaultStepConfiguration}.
+     *
+     * @param method to call on the step
+     * @param args the arguments to pass to the method
+     */
+    public DefaultStepConfiguration(final String method, final Object... args) {
+        this(null, method, args);
+    }
+
+    /**
+     * Creates a new {@code DefaultStepConfiguration}.
+     *
+     * @param methods a map of methods to call when configuring a step where the keys are the method names and the
+     *                values are the list of arguments to apply to that method
+     */
+    public DefaultStepConfiguration(final LinkedHashMap<String, List<Object>> methods) {
+        this(null, methods);
+    }
+
+    /**
+     * Creates a new {@code DefaultStepConfiguration} with a validation option to ensure that the configuration is
+     * applied to the right type of step.
+     *
+     * @param expects the step type that this configuration should be applied to
+     * @param method to call on the step
+     * @param args the arguments to pass to the method
+     */
+    public DefaultStepConfiguration(final Class<? extends Step> expects, final String method, final Object... args) {
+        if (null == method || method.isEmpty()) throw new IllegalArgumentException("method may not be null or empty");
+        conf = new LinkedHashMap<>();
+        conf.put(method, Arrays.asList(args));
+        this.expects = expects;
+    }
+
+    /**
+     * Creates a new {@code DefaultStepConfiguration} with a validation option to ensure that the configuration is
+     * applied to the right type of step.
+     *
+     * @param expects the step type that this configuration should be applied to
+     * @param methods a map of methods to call when configuring a step where the keys are the method names and the
+     *                values are the list of arguments to apply to that method
+     */
+    public DefaultStepConfiguration(final Class<? extends Step> expects, final LinkedHashMap<String, List<Object>> methods) {
+        if (null == methods || methods.isEmpty()) throw new IllegalArgumentException("methods may not be null or empty");
+        if (IteratorUtils.anyMatch(methods.keySet().iterator(), k -> null == k || k.isEmpty())) throw new IllegalArgumentException("no key of methods map may be null or empty");
+        conf = methods;
+        this.expects = expects;
+    }
+
+    private DefaultStepConfiguration() {
+        // for gyro's sake.........
+        conf = Collections.emptyMap();
+        expects = null;
+    }
+
+    @Override
+    public void accept(final Step step) {
+        final Optional<Class<? extends Step>> opt = Optional.ofNullable(expects);
+        if (opt.isPresent() && !opt.get().isAssignableFrom(step.getClass())) {
+            throw new IllegalStateException(String.format("Could not apply step configuration of %s to %s", conf, step.getClass().getName()));
+        }
+
+        for (Map.Entry<String, List<Object>> kv : conf.entrySet()) {
+            try {
+                MethodUtils.invokeMethod(step, kv.getKey(), kv.getValue().toArray());
+            } catch (NoSuchMethodException nsme) {
+                if (!step.getTraversal().asAdmin().getStrategies().getStrategy(RemoteStrategy.class).isPresent())
+                    throw new IllegalStateException(String.format("Step configuration of %s with args of %s cannot be applied to %s",
+                            kv.getKey(), kv.getValue(), step.getClass().getName()), nsme);
+            } catch (Exception ex) {
+                throw new IllegalStateException(String.format("Step configuration of %s with args of %s cannot be applied to %s",
+                        kv.getKey(), kv.getValue(), step.getClass().getName()), ex);
+            }
+        }
+    }
+
+    public static StepConfiguration create(final Configuration conf) {
+        final LinkedHashMap<String,List<Object>> m = new LinkedHashMap<>();
+        final Iterator<String> keys = conf.getKeys();
+        while (keys.hasNext()) {
+            final String key = keys.next();
+            m.put(key, conf.getList(key));
+        }
+        return new DefaultStepConfiguration(m);
+    }
+
+    @Override
+    public Configuration getConfiguration() {
+        return new MapConfiguration(conf);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final DefaultStepConfiguration that = (DefaultStepConfiguration) o;
+
+        return conf.equals(that.conf);
+    }
+
+    @Override
+    public int hashCode() {
+        return conf.hashCode();
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/99a4b368/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StepConfigurationProxy.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StepConfigurationProxy.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StepConfigurationProxy.java
new file mode 100644
index 0000000..6226900
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/StepConfigurationProxy.java
@@ -0,0 +1,50 @@
+/*
+ * 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.step.util;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration;
+
+import java.io.Serializable;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class StepConfigurationProxy<T extends StepConfiguration> implements Serializable {
+
+    private final Configuration configuration;
+    private final Class<T> stepConfigurationClass;
+
+    public StepConfigurationProxy(final T stepConfiguration) {
+        this((Class<T>) stepConfiguration.getClass(), stepConfiguration.getConfiguration());
+    }
+
+    public StepConfigurationProxy(final Class<T> stepConfigurationClass, final Configuration configuration) {
+        this.configuration = configuration;
+        this.stepConfigurationClass = stepConfigurationClass;
+    }
+
+    public Configuration getConfiguration() {
+        return this.configuration;
+    }
+
+    public Class<T> getStepConfigurationClass() {
+        return this.stepConfigurationClass;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/99a4b368/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java
new file mode 100644
index 0000000..6b3fc1c
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/DefaultStepConfigurationTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.step.util;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.MapConfiguration;
+import org.apache.commons.lang.reflect.FieldUtils;
+import org.apache.tinkerpop.gremlin.process.computer.traversal.step.map.PageRankVertexProgramStep;
+import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
+import org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException;
+import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
+import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
+import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.StepConfiguration;
+import org.apache.tinkerpop.gremlin.structure.util.empty.EmptyGraph;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class DefaultStepConfigurationTest {
+
+    @Test
+    public void shouldApplyDefaultConfiguration() throws Exception {
+        final Traversal t = __.V().pageRank().with(new DefaultStepConfiguration("modulateBy", "xxx"));
+        final Step s = t.asAdmin().getEndStep();
+        assertEquals("xxx", FieldUtils.readField(s, "pageRankProperty", true));
+    }
+
+    @Test
+    public void shouldApplyDefaultConfigurationWithClassValidation() throws Exception {
+        final Traversal t = __.V().pageRank().with(new DefaultStepConfiguration(PageRankVertexProgramStep.class, "modulateBy", "xxx"));
+        final Step s = t.asAdmin().getEndStep();
+        assertEquals("xxx", FieldUtils.readField(s, "pageRankProperty", true));
+    }
+
+    @Test
+    public void shouldApplyDefaultConfigurationInOrder() throws Exception {
+        final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>();
+        methods.put("setY", Collections.singletonList(100L));
+        methods.put("setX", Collections.singletonList("xxx"));
+        methods.put("setZ", Collections.singletonList("zzz" ));
+        final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods);
+        final MockStep step = new MockStep(__.__().asAdmin());
+
+        conf.accept(step);
+
+        assertThat(step.list, contains(100L, "Xxxx", "Zzzz"));
+    }
+
+    @Test
+    public void shouldGenerateConfiguration() throws Exception {
+        final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>();
+        methods.put("setY", Collections.singletonList(100L));
+        methods.put("setX", Collections.singletonList("xxx"));
+        methods.put("setZ", Collections.singletonList("zzz" ));
+        final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods);
+        final MapConfiguration c = (MapConfiguration) conf.getConfiguration();
+        c.setDelimiterParsingDisabled(false);
+
+        assertEquals(100L, c.getList("setY").get(0));
+        assertEquals("xxx", c.getList("setX").get(0));
+        assertEquals("zzz", c.getList("setZ").get(0));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldValidateClass() {
+        __.V().pageRank().with(new DefaultStepConfiguration(MockStep.class, "modulateBy", "xxx"));
+    }
+
+    @Test
+    public void shouldAllowNoSuchMethodIfUsingRemote() {
+        // create a fake remote
+        final GraphTraversalSource g = EmptyGraph.instance().traversal().withRemote(new RemoteConnection() {
+            @Override
+            public <E> Iterator<Traverser.Admin<E>> submit(final Traversal<?, E> traversal) throws RemoteConnectionException {
+                return null;
+            }
+
+            @Override
+            public <E> RemoteTraversal<?, E> submit(final Bytecode bytecode) throws RemoteConnectionException {
+                return null;
+            }
+
+            @Override
+            public void close() throws Exception {
+
+            }
+        });
+
+        // try to set a fake configuration option - lack of exception is good. not really sure how else to directly
+        // assert this
+        final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>();
+        methods.put("setFakeyFakerton", Collections.singletonList(100L));
+        final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods);
+        g.V().with(conf);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowNoSuchMethodUnlessUsingRemote() {
+        final GraphTraversalSource g = EmptyGraph.instance().traversal();
+
+        // try to set a fake configuration option
+        final LinkedHashMap<String, List<Object>> methods = new LinkedHashMap<>();
+        methods.put("setFakeyFakerton", Collections.singletonList(100L));
+        final StepConfiguration<Step> conf = new DefaultStepConfiguration(methods);
+        g.V().with(conf);
+    }
+
+    static class MockStep extends AbstractStep {
+
+        List<Object> list = new ArrayList<>();
+
+        MockStep(final Traversal.Admin t) {
+            super(t);
+        }
+
+        public void setX(final String s) {
+            list.add("X" + s);
+        }
+
+        public void setY(final Long s) {
+            list.add(s);
+        }
+
+        public void setZ(final String s) {
+            list.add("Z" + s);
+        }
+
+
+        @Override
+        protected Traverser.Admin processNextStart() throws NoSuchElementException {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/99a4b368/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs
new file mode 100644
index 0000000..a01ac1c
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/IStepConfiguration.cs
@@ -0,0 +1,32 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+namespace Gremlin.Net.Process.Traversal
+{
+    /// <summary>
+    ///     A configuration for a step supplied to the with() modulator of a traversal.
+    /// </summary>
+    public interface IStepConfiguration
+    {
+    }
+}
\ No newline at end of file