VisitorBase.java

  1. /*
  2.  *  Copyright (c) 2001-2024, Jean Tessier
  3.  *  All rights reserved.
  4.  *  
  5.  *  Redistribution and use in source and binary forms, with or without
  6.  *  modification, are permitted provided that the following conditions
  7.  *  are met:
  8.  *  
  9.  *      * Redistributions of source code must retain the above copyright
  10.  *        notice, this list of conditions and the following disclaimer.
  11.  *  
  12.  *      * Redistributions in binary form must reproduce the above copyright
  13.  *        notice, this list of conditions and the following disclaimer in the
  14.  *        documentation and/or other materials provided with the distribution.
  15.  *  
  16.  *      * Neither the name of Jean Tessier nor the names of his contributors
  17.  *        may be used to endorse or promote products derived from this software
  18.  *        without specific prior written permission.
  19.  *  
  20.  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21.  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22.  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23.  *  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
  24.  *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25.  *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26.  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27.  *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28.  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29.  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30.  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  */

  32. package com.jeantessier.dependency;

  33. import java.util.*;

  34. import org.apache.logging.log4j.*;

  35. /**
  36.  *  This is a basic implementation of Visitor.
  37.  *
  38.  *  @see Visitor
  39.  *  @author Jean Tessier
  40.  */
  41. public abstract class VisitorBase implements Visitor {
  42.     protected static TraversalStrategy getDefaultStrategy() {
  43.         return new ComprehensiveTraversalStrategy();
  44.     }

  45.     private final TraversalStrategy strategy;

  46.     private final LinkedList<Node> currentNodes = new LinkedList<>();

  47.     public VisitorBase() {
  48.         this(getDefaultStrategy());
  49.     }

  50.     public VisitorBase(TraversalStrategy strategy) {
  51.         this.strategy = strategy;
  52.     }

  53.     protected TraversalStrategy getStrategy() {
  54.         return strategy;
  55.     }

  56.     public void traverseNodes(Collection<? extends Node> nodes) {
  57.         Visitor.super.traverseNodes(getStrategy().order(nodes));
  58.     }

  59.     public void traverseInbound(Collection<? extends Node> nodes) {
  60.         Visitor.super.traverseInbound(getStrategy().order(nodes));
  61.     }

  62.     public void traverseOutbound(Collection<? extends Node> nodes) {
  63.         Visitor.super.traverseOutbound(getStrategy().order(nodes));
  64.     }

  65.     protected Node getCurrentNode() {
  66.         Node result = null;

  67.         if (!currentNodes.isEmpty()) {
  68.             result = currentNodes.getLast();
  69.         }

  70.         LogManager.getLogger(getClass()).debug("{}: {}", currentNodes, result);

  71.         return result;
  72.     }

  73.     protected void pushNode(Node currentNode) {
  74.         LogManager.getLogger(getClass()).debug("{} + {}", currentNodes, currentNode);
  75.         currentNodes.addLast(currentNode);
  76.     }

  77.     protected Node popNode() {
  78.         Node result = currentNodes.removeLast();

  79.         LogManager.getLogger(getClass()).debug("{} -> {}", currentNodes, result);

  80.         return result;
  81.     }

  82.     public void visitPackageNode(PackageNode node) {
  83.         boolean inScope = isInScope(node);
  84.        
  85.         if (inScope) {
  86.             preprocessPackageNode(node);
  87.            
  88.             if (getStrategy().doPreOutboundTraversal()) {
  89.                 traverseOutbound(node.getOutboundDependencies());
  90.             }
  91.            
  92.             if (getStrategy().doPreInboundTraversal()) {
  93.                 traverseInbound(node.getInboundDependencies());
  94.             }
  95.            
  96.             preprocessAfterDependenciesPackageNode(node);
  97.         }
  98.            
  99.         traverseNodes(node.getClasses());

  100.         if (inScope) {
  101.             postprocessBeforeDependenciesPackageNode(node);

  102.             if (getStrategy().doPostOutboundTraversal()) {
  103.                 traverseOutbound(node.getOutboundDependencies());
  104.             }
  105.            
  106.             if (getStrategy().doPostInboundTraversal()) {
  107.                 traverseInbound(node.getInboundDependencies());
  108.             }
  109.            
  110.             postprocessPackageNode(node);
  111.         }
  112.     }

  113.     protected boolean isInScope(PackageNode node) {
  114.         return getStrategy().isInScope(node);
  115.     }

  116.     protected void preprocessPackageNode(PackageNode node) {
  117.         pushNode(node);
  118.     }
  119.    
  120.     protected void preprocessAfterDependenciesPackageNode(PackageNode node) {
  121.         // Do nothing
  122.     }
  123.    
  124.     protected void postprocessBeforeDependenciesPackageNode(PackageNode node) {
  125.         // Do nothing
  126.     }
  127.    
  128.     protected void postprocessPackageNode(PackageNode node) {
  129.         if (node.equals(getCurrentNode())) {
  130.             popNode();
  131.         }
  132.     }

  133.     public void visitClassNode(ClassNode node) {
  134.         boolean inScope = isInScope(node);
  135.        
  136.         if (inScope) {
  137.             preprocessClassNode(node);
  138.            
  139.             if (getStrategy().doPreOutboundTraversal()) {
  140.                 traverseOutbound(node.getOutboundDependencies());
  141.             }
  142.            
  143.             if (getStrategy().doPreInboundTraversal()) {
  144.                 traverseInbound(node.getInboundDependencies());
  145.             }

  146.             preprocessAfterDependenciesClassNode(node);
  147.         }
  148.        
  149.         traverseNodes(node.getFeatures());
  150.            
  151.         if (inScope) {
  152.             postprocessBeforeDependenciesClassNode(node);

  153.             if (getStrategy().doPostOutboundTraversal()) {
  154.                 traverseOutbound(node.getOutboundDependencies());
  155.             }
  156.            
  157.             if (getStrategy().doPostInboundTraversal()) {
  158.                 traverseInbound(node.getInboundDependencies());
  159.             }
  160.            
  161.             postprocessClassNode(node);
  162.         }
  163.     }

  164.     protected boolean isInScope(ClassNode node) {
  165.         return getStrategy().isInScope(node);
  166.     }

  167.     protected void preprocessClassNode(ClassNode node) {
  168.         pushNode(node);
  169.     }
  170.    
  171.     protected void preprocessAfterDependenciesClassNode(ClassNode node) {
  172.         // Do nothing
  173.     }

  174.     protected void postprocessBeforeDependenciesClassNode(ClassNode node) {
  175.         // Do nothing
  176.     }

  177.     protected void postprocessClassNode(ClassNode node) {
  178.         if (node.equals(getCurrentNode())) {
  179.             popNode();
  180.         }
  181.     }

  182.     public void visitFeatureNode(FeatureNode node) {
  183.         if (isInScope(node)) {
  184.             preprocessFeatureNode(node);
  185.            
  186.             if (getStrategy().doPreOutboundTraversal()) {
  187.                 traverseOutbound(node.getOutboundDependencies());
  188.             }
  189.            
  190.             if (getStrategy().doPreInboundTraversal()) {
  191.                 traverseInbound(node.getInboundDependencies());
  192.             }
  193.            
  194.             if (getStrategy().doPostOutboundTraversal()) {
  195.                 traverseOutbound(node.getOutboundDependencies());
  196.             }
  197.            
  198.             if (getStrategy().doPostInboundTraversal()) {
  199.                 traverseInbound(node.getInboundDependencies());
  200.             }
  201.            
  202.             postprocessFeatureNode(node);
  203.         }
  204.     }

  205.     protected boolean isInScope(FeatureNode node) {
  206.         return getStrategy().isInScope(node);
  207.     }

  208.     protected void preprocessFeatureNode(FeatureNode node) {
  209.         pushNode(node);
  210.     }
  211.    
  212.     protected void postprocessFeatureNode(FeatureNode node) {
  213.         if (node.equals(getCurrentNode())) {
  214.             popNode();
  215.         }
  216.     }
  217. }