blob: 2fe1b8fed9a66258e8ee5e182139f694a581d777 [file] [log] [blame]
/*
* 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;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.tinkerpop.gremlin.process.computer.Computer;
import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
import org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy;
import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SackStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SideEffectStrategy;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
/**
* A {@code TraversalSource} is used to create {@link Traversal} instances.
* A traversal source can generate any number of {@link Traversal} instances.
* A traversal source is primarily composed of a {@link Graph} and a {@link TraversalStrategies}.
* Various {@code withXXX}-based methods are used to configure the traversal strategies (called "configurations").
* Various other methods (dependent on the traversal source type) will then generate a traversal given the graph and configured strategies (called "spawns").
* A traversal source is immutable in that fluent chaining of configurations create new traversal sources.
* This is unlike {@link Traversal} and {@link GraphComputer}, where chained methods configure the same instance.
* Every traversal source implementation must maintain two constructors to enable proper reflection-based construction.
* <p/>
* {@code TraversalSource(Graph)} and {@code TraversalSource(Graph,TraversalStrategies)}
*
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
public interface TraversalSource extends Cloneable, AutoCloseable {
/**
* @deprecated As of release 3.3.5, replaced by {@link RemoteConnection#GREMLIN_REMOTE}.
*/
@Deprecated
public static final String GREMLIN_REMOTE = "gremlin.remote.";
/**
* @deprecated As of release 3.3.5, replaced by {@link RemoteConnection#GREMLIN_REMOTE_CONNECTION_CLASS}.
*/
@Deprecated
public static final String GREMLIN_REMOTE_CONNECTION_CLASS = GREMLIN_REMOTE + "remoteConnectionClass";
/**
* Get the {@link TraversalStrategies} associated with this traversal source.
*
* @return the traversal strategies of the traversal source
*/
public TraversalStrategies getStrategies();
/**
* Get the {@link Graph} associated with this traversal source.
*
* @return the graph of the traversal source
*/
public Graph getGraph();
/**
* Get the {@link Bytecode} associated with the current state of this traversal source.
*
* @return the traversal source byte code
*/
public Bytecode getBytecode();
/////////////////////////////
public static class Symbols {
private Symbols() {
// static fields only
}
public static final String withSack = "withSack";
public static final String withStrategies = "withStrategies";
public static final String withoutStrategies = "withoutStrategies";
public static final String withComputer = "withComputer";
public static final String withSideEffect = "withSideEffect";
public static final String withRemote = "withRemote";
}
/////////////////////////////
/**
* Add an arbitrary collection of {@link TraversalStrategy} instances to the traversal source.
*
* @param traversalStrategies a collection of traversal strategies to add
* @return a new traversal source with updated strategies
*/
public default TraversalSource withStrategies(final TraversalStrategy... traversalStrategies) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(traversalStrategies);
clone.getBytecode().addSource(TraversalSource.Symbols.withStrategies, traversalStrategies);
for (final TraversalStrategy traversalStrategy : traversalStrategies) {
if (traversalStrategy instanceof VertexProgramStrategy) {
((VertexProgramStrategy) traversalStrategy).addGraphComputerStrategies(clone);
}
}
return clone;
}
/**
* Remove an arbitrary collection of {@link TraversalStrategy} classes from the traversal source.
*
* @param traversalStrategyClasses a collection of traversal strategy classes to remove
* @return a new traversal source with updated strategies
*/
@SuppressWarnings({"unchecked", "varargs"})
public default TraversalSource withoutStrategies(final Class<? extends TraversalStrategy>... traversalStrategyClasses) {
final TraversalSource clone = this.clone();
clone.getStrategies().removeStrategies(traversalStrategyClasses);
clone.getBytecode().addSource(TraversalSource.Symbols.withoutStrategies, traversalStrategyClasses);
return clone;
}
/**
* Add a {@link Computer} that will generate a {@link GraphComputer} from the {@link Graph} that will be used to execute the traversal.
* This adds a {@link VertexProgramStrategy} to the strategies.
*
* @param computer a builder to generate a graph computer from the graph
* @return a new traversal source with updated strategies
*/
public default TraversalSource withComputer(final Computer computer) {
return this.withStrategies(new VertexProgramStrategy(computer));
}
/**
* Add a {@link GraphComputer} class used to execute the traversal.
* This adds a {@link VertexProgramStrategy} to the strategies.
*
* @param graphComputerClass the graph computer class
* @return a new traversal source with updated strategies
*/
public default TraversalSource withComputer(final Class<? extends GraphComputer> graphComputerClass) {
return this.withStrategies(new VertexProgramStrategy(Computer.compute(graphComputerClass)));
}
/**
* Add the standard {@link GraphComputer} of the graph that will be used to execute the traversal.
* This adds a {@link VertexProgramStrategy} to the strategies.
*
* @return a new traversal source with updated strategies
*/
public default TraversalSource withComputer() {
return this.withStrategies(new VertexProgramStrategy(Computer.compute()));
}
/**
* Add a sideEffect to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SideEffectStrategy} to the strategies.
*
* @param key the key of the sideEffect
* @param initialValue a supplier that produces the initial value of the sideEffect
* @param reducer a reducer to merge sideEffect mutations into a single result
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSideEffect(final String key, final Supplier<A> initialValue, final BinaryOperator<A> reducer) {
final TraversalSource clone = this.clone();
SideEffectStrategy.addSideEffect(clone.getStrategies(), key, (A) initialValue, reducer);
clone.getBytecode().addSource(TraversalSource.Symbols.withSideEffect, key, initialValue, reducer);
return clone;
}
/**
* Add a sideEffect to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SideEffectStrategy} to the strategies.
*
* @param key the key of the sideEffect
* @param initialValue the initial value of the sideEffect
* @param reducer a reducer to merge sideEffect mutations into a single result
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSideEffect(final String key, final A initialValue, final BinaryOperator<A> reducer) {
final TraversalSource clone = this.clone();
SideEffectStrategy.addSideEffect(clone.getStrategies(), key, initialValue, reducer);
clone.getBytecode().addSource(TraversalSource.Symbols.withSideEffect, key, initialValue, reducer);
return clone;
}
/**
* Add a sideEffect to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SideEffectStrategy} to the strategies.
*
* @param key the key of the sideEffect
* @param initialValue a supplier that produces the initial value of the sideEffect
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSideEffect(final String key, final Supplier<A> initialValue) {
final TraversalSource clone = this.clone();
SideEffectStrategy.addSideEffect(clone.getStrategies(), key, (A) initialValue, null);
clone.getBytecode().addSource(TraversalSource.Symbols.withSideEffect, key, initialValue);
return clone;
}
/**
* Add a sideEffect to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SideEffectStrategy} to the strategies.
*
* @param key the key of the sideEffect
* @param initialValue the initial value of the sideEffect
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSideEffect(final String key, final A initialValue) {
final TraversalSource clone = this.clone();
SideEffectStrategy.addSideEffect(clone.getStrategies(), key, initialValue, null);
clone.getBytecode().addSource(TraversalSource.Symbols.withSideEffect, key, initialValue);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue a supplier that produces the initial value of the sideEffect
* @param splitOperator the sack split operator
* @param mergeOperator the sack merge operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final Supplier<A> initialValue, final UnaryOperator<A> splitOperator, final BinaryOperator<A> mergeOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(initialValue).splitOperator(splitOperator).mergeOperator(mergeOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, splitOperator, mergeOperator);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue the initial value of the sideEffect
* @param splitOperator the sack split operator
* @param mergeOperator the sack merge operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final A initialValue, final UnaryOperator<A> splitOperator, final BinaryOperator<A> mergeOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(new ConstantSupplier<>(initialValue)).splitOperator(splitOperator).mergeOperator(mergeOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, splitOperator, mergeOperator);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue the initial value of the sideEffect
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final A initialValue) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(new ConstantSupplier<>(initialValue)).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue a supplier that produces the initial value of the sideEffect
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final Supplier<A> initialValue) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(initialValue).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue a supplier that produces the initial value of the sideEffect
* @param splitOperator the sack split operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final Supplier<A> initialValue, final UnaryOperator<A> splitOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(initialValue).splitOperator(splitOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, splitOperator);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue the initial value of the sideEffect
* @param splitOperator the sack split operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final A initialValue, final UnaryOperator<A> splitOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(new ConstantSupplier<>(initialValue)).splitOperator(splitOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, splitOperator);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue a supplier that produces the initial value of the sideEffect
* @param mergeOperator the sack merge operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final Supplier<A> initialValue, final BinaryOperator<A> mergeOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(initialValue).mergeOperator(mergeOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, mergeOperator);
return clone;
}
/**
* Add a sack to be used throughout the life of a spawned {@link Traversal}.
* This adds a {@link SackStrategy} to the strategies.
*
* @param initialValue the initial value of the sideEffect
* @param mergeOperator the sack merge operator
* @return a new traversal source with updated strategies
*/
public default <A> TraversalSource withSack(final A initialValue, final BinaryOperator<A> mergeOperator) {
final TraversalSource clone = this.clone();
clone.getStrategies().addStrategies(SackStrategy.<A>build().initialValue(new ConstantSupplier<>(initialValue)).mergeOperator(mergeOperator).create());
clone.getBytecode().addSource(TraversalSource.Symbols.withSack, initialValue, mergeOperator);
return clone;
}
/**
* Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
* Expects key for {@link RemoteConnection#GREMLIN_REMOTE_CONNECTION_CLASS} as well as any configuration required by
* the underlying {@link RemoteConnection} which will be instantiated. Note that the {@code Configuration} object
* is passed down without change to the creation of the {@link RemoteConnection} instance.
*
* @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(Configuration)}.
* @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
*/
@Deprecated
public default TraversalSource withRemote(final Configuration conf) {
return withRemote(RemoteConnection.from(conf));
}
/**
* Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
* Calls {@link #withRemote(Configuration)} after reading the properties file specified.
*
* @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(String)}.
* @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
*/
@Deprecated
public default TraversalSource withRemote(final String configFile) throws Exception {
return withRemote(new PropertiesConfiguration(configFile));
}
/**
* Configures the {@code TraversalSource} as a "remote" to issue the {@link Traversal} for execution elsewhere.
* Implementations should track {@link RemoteConnection} instances that are created and call
* {@link RemoteConnection#close()} on them when the {@code TraversalSource} itself is closed.
*
* @param connection the {@link RemoteConnection} instance to use to submit the {@link Traversal}.
* @deprecated As of release 3.3.5, replaced by {@link AnonymousTraversalSource#withRemote(RemoteConnection)}.
* @see <a href="https://issues.apache.org/jira/browse/TINKERPOP-2078">TINKERPOP-2078</a>
*/
@Deprecated
public TraversalSource withRemote(final RemoteConnection connection);
public default Optional<Class> getAnonymousTraversalClass() {
return Optional.empty();
}
/**
* The clone-method should be used to create immutable traversal sources with each call to a configuration "withXXX"-method.
* The clone-method should clone the {@link Bytecode}, {@link TraversalStrategies}, mutate the cloned strategies accordingly,
* and then return the cloned traversal source leaving the original unaltered.
*
* @return the cloned traversal source
*/
@SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
public TraversalSource clone();
@Override
public default void close() throws Exception {
// do nothing
}
}