You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by dk...@apache.org on 2018/05/31 21:08:07 UTC
[21/23] 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/939674a5
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/939674a5
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/939674a5
Branch: refs/heads/shortest-path-wip
Commit: 939674a5da218566628e54b63a30b98883367036
Parents: 6a40535
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri May 25 16:02:59 2018 -0400
Committer: Daniel Kuppitz <da...@hotmail.com>
Committed: Thu May 31 12:46:10 2018 -0700
----------------------------------------------------------------------
.../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/939674a5/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/939674a5/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/939674a5/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/939674a5/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