// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.query.profile; /** * Instances of this is used to visit nodes in a graph of query profiles * * * Visitor are called in the following sequence on each query profile: * enter=enter(referenceName); * onQueryProfile(this) * if (enter) { * getLocalKey() * ...calls on nested content found in variants, this and inherited, in that order * leave(referenceName) * } * * The first enter call will be on the root node, which has an empt reference name. * * * @author bratseth */ abstract class QueryProfileVisitor { /** * Called when a new nested profile in the graph is entered. * This default implementation does nothing but returning true. * If the node is entered (if true is returned from this), a corresponding {@link #leave(String)} call will happen * later. * * @param name the name this profile is nested as, or the empty string if we are entering the root profile * @return whether we should visit the content of this node or not */ public boolean enter(String name) { return true; } /** * Called when the last {@link #enter(String) entered} nested profile is left. * That is: One leave call is made for each enter call which returns true, * but due to nesting those calls are not necessarily alternating. * This default implementation does nothing. */ public void leave(String name) { } /** * Called when a value (not a query profile) is encountered. * * @param localName the local name of this value (the full name, if needed, must be reconstructed * by the information given by the history of {@link #enter(String)} and {@link #leave(String)} calls * @param value the value * @param binding the binding this holds for * @param owner the query profile having this value, or null only when profile is the root profile * @param variant the variant having this value, or null if it is not in a variant */ public abstract void onValue(String localName, Object value, DimensionBinding binding, QueryProfile owner, DimensionValues variant); /** * Called when a query profile is encountered. * * @param profile the query profile reference encountered * @param binding the binding this holds for * @param owner the profile making this reference, or null only when profile is the root profile * @param variant the variant having this value, or null if it is not in a variant */ public abstract void onQueryProfile(QueryProfile profile, DimensionBinding binding, QueryProfile owner, DimensionValues variant); /** Returns whether this visitor is done visiting what it needed to visit at this point */ public abstract boolean isDone(); /** Returns whether we should, at this point, visit inherited profiles. This default implementation returns true */ public boolean visitInherited() { return true; } /** * Returns the current local key which should be visited in the last {@link #enter(String) entered} sub-profile * (or in the top level profile if none is entered), or null to visit all content */ public abstract String getLocalKey(); /** * Calls onValue or onQueryProfile on this and visits the content if it's a profile * * @param variant the variant having this value, or null if it is not in a variant */ final void acceptValue(String key, Object value, DimensionBinding dimensionBinding, QueryProfile owner, DimensionValues variant) { if (value == null) return; if (value instanceof QueryProfile) { QueryProfile queryProfileValue = (QueryProfile)value; queryProfileValue.acceptAndEnter(key, this, dimensionBinding.createFor(queryProfileValue.getDimensions()), owner); } else { onValue(key, value, dimensionBinding, owner, variant); } } }