blob: 2aa4153e7aacdd381732a034b54234f2cb880825 [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.BaseConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.ProfileStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy;
import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy;
import java.io.Serializable;
import java.util.Collections;
import java.util.Set;
/**
* A {@link TraversalStrategy} defines a particular atomic operation for mutating a {@link Traversal} prior to its evaluation.
* There are 5 pre-defined "traversal categories": {@link DecorationStrategy}, {@link OptimizationStrategy}, {@link ProviderOptimizationStrategy}, {@link FinalizationStrategy}, and {@link VerificationStrategy}.
* Strategies within a category are sorted amongst themselves and then category sorts are applied in the ordered specified previous.
* That is, decorations are applied, then optimizations, then provider optimizations, then finalizations, and finally, verifications.
* If a strategy does not fit within the specified categories, then it can simply implement {@link TraversalStrategy} and can have priors/posts that span categories.
* <p/>
* A traversal strategy should be a final class as various internal operations on a strategy are based on its ability to be assigned to more general classes.
* A traversal strategy should typically be stateless with a public static <code>instance()</code> method.
* However, at limit, a traversal strategy can have a state defining constructor (typically via a "builder"), but that state can not mutate once instantiated.
*
* @author Marko A. Rodriguez (http://markorodriguez.com)
* @author Matthias Broecheler (me@matthiasb.com)
*/
public interface TraversalStrategy<S extends TraversalStrategy> extends Serializable, Comparable<Class<? extends TraversalStrategy>> {
public static final String STRATEGY = "strategy";
public void apply(final Traversal.Admin<?, ?> traversal);
/**
* The set of strategies that must be executed before this strategy is executed.
* If there are no ordering requirements, the default implementation returns an empty set.
*
* @return the set of strategies that must be executed prior to this one.
*/
public default Set<Class<? extends S>> applyPrior() {
return Collections.emptySet();
}
/**
* The set of strategies that must be executed after this strategy is executed.
* If there are no ordering requirements, the default implementation returns an empty set.
*
* @return the set of strategies that must be executed post this one
*/
public default Set<Class<? extends S>> applyPost() {
return Collections.emptySet();
}
/**
* The type of traversal strategy -- i.e. {@link DecorationStrategy}, {@link OptimizationStrategy}, {@link FinalizationStrategy}, or {@link VerificationStrategy}.
*
* @return the traversal strategy category class
*/
public default Class<S> getTraversalCategory() {
return (Class) TraversalStrategy.class;
}
/**
* Get the configuration representation of this strategy.
* This is useful for converting a strategy into a serialized form.
*
* @return the configuration used to create this strategy
*/
public default Configuration getConfiguration() {
return new BaseConfiguration();
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
return 0;
}
/**
* Implemented by strategies that adds "application logic" to the traversal (e.g. {@link PartitionStrategy}).
*/
public interface DecorationStrategy extends TraversalStrategy<DecorationStrategy> {
@Override
public default Class<DecorationStrategy> getTraversalCategory() {
return DecorationStrategy.class;
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
if (otherTraversalCategory.equals(DecorationStrategy.class))
return 0;
else if (otherTraversalCategory.equals(OptimizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(ProviderOptimizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(FinalizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(VerificationStrategy.class))
return -1;
else
return 0;
}
}
/**
* Implemented by strategies that rewrite the traversal to be more efficient, but with the same semantics
* (e.g. {@link CountStrategy}). During a re-write ONLY TinkerPop steps should be used.
* For strategies that utilize provider specific steps, use {@link ProviderOptimizationStrategy}.
*/
public interface OptimizationStrategy extends TraversalStrategy<OptimizationStrategy> {
@Override
public default Class<OptimizationStrategy> getTraversalCategory() {
return OptimizationStrategy.class;
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
if (otherTraversalCategory.equals(DecorationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(OptimizationStrategy.class))
return 0;
else if (otherTraversalCategory.equals(ProviderOptimizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(FinalizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(VerificationStrategy.class))
return -1;
else
return 0;
}
}
/**
* Implemented by strategies that rewrite the traversal to be more efficient, but with the same semantics.
* This is for graph system/language/driver providers that want to rewrite a traversal using provider specific steps.
*/
public interface ProviderOptimizationStrategy extends TraversalStrategy<ProviderOptimizationStrategy> {
@Override
public default Class<ProviderOptimizationStrategy> getTraversalCategory() {
return ProviderOptimizationStrategy.class;
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
if (otherTraversalCategory.equals(DecorationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(OptimizationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(ProviderOptimizationStrategy.class))
return 0;
else if (otherTraversalCategory.equals(FinalizationStrategy.class))
return -1;
else if (otherTraversalCategory.equals(VerificationStrategy.class))
return -1;
else
return 0;
}
}
/**
* Implemented by strategies that do final behaviors that require a fully compiled traversal to work (e.g.
* {@link ProfileStrategy}).
*/
public interface FinalizationStrategy extends TraversalStrategy<FinalizationStrategy> {
@Override
public default Class<FinalizationStrategy> getTraversalCategory() {
return FinalizationStrategy.class;
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
if (otherTraversalCategory.equals(DecorationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(OptimizationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(ProviderOptimizationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(FinalizationStrategy.class))
return 0;
else if (otherTraversalCategory.equals(VerificationStrategy.class))
return -1;
else
return 0;
}
}
/**
* Implemented by strategies where there is no more behavioral tweaking of the traversal required. Strategies that
* implement this category will simply analyze the traversal and throw exceptions if the traversal is not correct
* for the execution context (e.g. {@link LambdaRestrictionStrategy}).
*/
public interface VerificationStrategy extends TraversalStrategy<VerificationStrategy> {
@Override
public default Class<VerificationStrategy> getTraversalCategory() {
return VerificationStrategy.class;
}
@Override
public default int compareTo(final Class<? extends TraversalStrategy> otherTraversalCategory) {
if (otherTraversalCategory.equals(DecorationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(OptimizationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(ProviderOptimizationStrategy.class))
return 1;
else if (otherTraversalCategory.equals(FinalizationStrategy.class))
return 1;
else
return 0;
}
}
}