/* * 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 6 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; } } }