Github user spmallette commented on a diff in the pull request: https://github.com/apache/tinkerpop/pull/902#discussion_r209362047 --- Diff: sparql-gremlin/src/main/java/org/apache/tinkerpop/gremlin/sparql/process/traversal/dsl/sparql/SparqlTraversalSource.java --- @@ -0,0 +1,155 @@ +/* + * 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.sparql.process.traversal.dsl.sparql; + +import org.apache.commons.configuration.Configuration; +import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection; +import org.apache.tinkerpop.gremlin.process.remote.traversal.strategy.decoration.RemoteStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +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.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.map.ConstantStep; +import org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.InjectStep; +import org.apache.tinkerpop.gremlin.sparql.process.traversal.strategy.SparqlStrategy; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Transaction; +import org.apache.tinkerpop.gremlin.structure.util.StringFactory; + +/** + * A {@link TraversalSource} implementation that spawns {@link SparqlTraversal} instances. + * + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class SparqlTraversalSource implements TraversalSource { + protected transient RemoteConnection connection; + protected final Graph graph; + protected TraversalStrategies strategies; + protected Bytecode bytecode = new Bytecode(); + + public SparqlTraversalSource(final Graph graph, final TraversalStrategies traversalStrategies) { + this.graph = graph; + this.strategies = traversalStrategies; + } + + public SparqlTraversalSource(final Graph graph) { + this(graph, TraversalStrategies.GlobalCache.getStrategies(graph.getClass())); + } + + @Override + public TraversalStrategies getStrategies() { + return this.strategies; + } + + @Override + public Graph getGraph() { + return this.graph; + } + + @Override + public Bytecode getBytecode() { + return this.bytecode; + } + + @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") + public SparqlTraversalSource clone() { + try { + final SparqlTraversalSource clone = (SparqlTraversalSource) super.clone(); + clone.strategies = this.strategies.clone(); + clone.bytecode = this.bytecode.clone(); + return clone; + } catch (final CloneNotSupportedException e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + //// CONFIGURATIONS + + @Override + public SparqlTraversalSource withStrategies(final TraversalStrategy... traversalStrategies) { + return (SparqlTraversalSource) TraversalSource.super.withStrategies(traversalStrategies); + } + + @Override + @SuppressWarnings({"unchecked"}) + public SparqlTraversalSource withoutStrategies(final Class<? extends TraversalStrategy>... traversalStrategyClasses) { + return (SparqlTraversalSource) TraversalSource.super.withoutStrategies(traversalStrategyClasses); + } + + @Override + public SparqlTraversalSource withRemote(final Configuration conf) { + return (SparqlTraversalSource) TraversalSource.super.withRemote(conf); + } + + @Override + public SparqlTraversalSource withRemote(final String configFile) throws Exception { + return (SparqlTraversalSource) TraversalSource.super.withRemote(configFile); + } + + @Override + public SparqlTraversalSource withRemote(final RemoteConnection connection) { + try { + // check if someone called withRemote() more than once, so just release resources on the initial + // connection as you can't have more than one. maybe better to toss IllegalStateException?? + if (this.connection != null) + this.connection.close(); + } catch (Exception ignored) { + // not sure there's anything to do here + } + + this.connection = connection; + final TraversalSource clone = this.clone(); + clone.getStrategies().addStrategies(new RemoteStrategy(connection)); + return (SparqlTraversalSource) clone; + } + + /** + * The start step for a SPARQL based traversal that accepts a string representation of the query to execute. + */ + public <S> SparqlTraversal<S,?> sparql(final String query) { + final SparqlTraversalSource clone = this.clone(); + clone.getStrategies().addStrategies(SparqlStrategy.instance()); + + // this is a bit of a hack to get remote traversals to work cleanly. on the remote side, we'd expect a + // GraphTraversalSource not a SparqlTraversalSource (given that sparql-gremlin is to be implemented in the + // DSL pattern). Instead of just sending the constant() step with the sparql query we also include an + // inject() step which will be recognized by a GraphTraversalSource on the remote side. Since SparqlStrategy + // wholly replaces both of these steps, the traversal bytecode can be read properly. + clone.bytecode.addStep(GraphTraversal.Symbols.inject); + clone.bytecode.addStep(GraphTraversal.Symbols.constant, query); --- End diff -- uh....yeah, i guess the `inject()` could be used that way. it's been a long time, but i remember marko wanting to use `constant()` and but i needed `inject()` to start the traversal so that's how the two got in there. I prefer the use of `constant()` as the holder for the sparql string, but let me sleep on it. Perhaps it's better to change it - the whole traversal gets wiped out anyway by the `SparqlStrategy` so, maybe it doesn't matter what step I transport the sparql in.
---