content: /*
   * 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.calcite.plan;
  
  import org.apache.calcite.rel.RelNode;
  
  import org.checkerframework.checker.nullness.qual.Nullable;
  
  import java.util.EventListener;
  import java.util.EventObject;
  
  /**
   * RelOptListener defines an interface for listening to events which occur
   * during the optimization process.
   */
  public interface RelOptListener extends EventListener {
    //~ Methods ----------------------------------------------------------------
  
    /**
     * Notifies this listener that a relational expression has been registered
     * with a particular equivalence class after an equivalence has been either
     * detected or asserted. Equivalence classes may be either logical (all
     * expressions which yield the same result set) or physical (all expressions
     * which yield the same result set with a particular calling convention).
     *
     * @param event details about the event
     */
    void relEquivalenceFound(RelEquivalenceEvent event);
  
    /**
     * Notifies this listener that an optimizer rule is being applied to a
     * particular relational expression. This rule is called twice; once before
     * the rule is invoked, and once after. Note that the rel attribute of the
     * event is always the old expression.
     *
     * @param event details about the event
     */
    void ruleAttempted(RuleAttemptedEvent event);
  
    /**
     * Notifies this listener that an optimizer rule has been successfully
     * applied to a particular relational expression, resulting in a new
     * equivalent expression (relEquivalenceFound will also be called unless the
     * new expression is identical to an existing one). This rule is called
     * twice; once before registration of the new rel, and once after. Note that
     * the rel attribute of the event is always the new expression; to get the
     * old expression, use event.getRuleCall().rels[0].
     *
     * @param event details about the event
     */
    void ruleProductionSucceeded(RuleProductionEvent event);
  
    /**
     * Notifies this listener that a relational expression is no longer of
     * interest to the planner.
     *
     * @param event details about the event
     */
    void relDiscarded(RelDiscardedEvent event);
  
    /**
     * Notifies this listener that a relational expression has been chosen as
     * part of the final implementation of the query plan. After the plan is
     * complete, this is called one more time with null for the rel.
     *
     * @param event details about the event
     */
    void relChosen(RelChosenEvent event);
  
    //~ Inner Classes ----------------------------------------------------------
  
    /**
     * Event class for abstract event dealing with a relational expression. The
     * source of an event is typically the RelOptPlanner which initiated it.
     */
    abstract class RelEvent extends EventObject {
      private final @Nullable RelNode rel;
  
      protected RelEvent(Object eventSource, @Nullable RelNode rel) {
        super(eventSource);
        this.rel = rel;
      }
  
      public @Nullable RelNode getRel() {
        return rel;
      }
    }
  
    /** Event indicating that a relational expression has been chosen. */
    class RelChosenEvent extends RelEvent {
      public RelChosenEvent(Object eventSource, @Nullable RelNode rel) {
        super(eventSource, rel);
      }
    }
  
    /** Event indicating that a relational expression has been found to
     * be equivalent to an equivalence class. */
    class RelEquivalenceEvent extends RelEvent {
      private final Object equivalenceClass;
      private final boolean isPhysical;
  
      public RelEquivalenceEvent(
          Object eventSource,
          RelNode rel,
          Object equivalenceClass,
          boolean isPhysical) {
        super(eventSource, rel);
        this.equivalenceClass = equivalenceClass;
        this.isPhysical = isPhysical;
      }
  
      public Object getEquivalenceClass() {
        return equivalenceClass;
      }
  
      public boolean isPhysical() {
        return isPhysical;
      }
    }
  
    /** Event indicating that a relational expression has been discarded. */
    class RelDiscardedEvent extends RelEvent {
      public RelDiscardedEvent(Object eventSource, RelNode rel) {
        super(eventSource, rel);
      }
    }
  
    /** Event indicating that a planner rule has fired. */
    abstract class RuleEvent extends RelEvent {
      private final RelOptRuleCall ruleCall;
  
      protected RuleEvent(
          Object eventSource,
          RelNode rel,
          RelOptRuleCall ruleCall) {
        super(eventSource, rel);
        this.ruleCall = ruleCall;
      }
  
      public RelOptRuleCall getRuleCall() {
        return ruleCall;
      }
    }
  
    /** Event indicating that a planner rule has been attempted. */
    class RuleAttemptedEvent extends RuleEvent {
      private final boolean before;
  
      public RuleAttemptedEvent(
          Object eventSource,
          RelNode rel,
          RelOptRuleCall ruleCall,
          boolean before) {
        super(eventSource, rel, ruleCall);
        this.before = before;
      }
  
      public boolean isBefore() {
        return before;
      }
    }
  
    /** Event indicating that a planner rule has produced a result. */
    class RuleProductionEvent extends RuleAttemptedEvent {
      public RuleProductionEvent(
          Object eventSource,
          RelNode rel,
          RelOptRuleCall ruleCall,
          boolean before) {
        super(eventSource, rel, ruleCall, before);
      }
    }
  }
  