All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ch.cern.ZKTree Maven / Gradle / Ivy

There is a newer version: 1.0.1-21
Show newest version
/*
* Copyright © 2020, CERN
* This software is distributed under the terms of the MIT Licence,
* copied verbatim in the file 'LICENSE'. In applying this licence,
* CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

//CPD-OFF
package ch.cern;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.NoAuthException;
import org.apache.zookeeper.data.ACL;

/**
 * Class that handles operations on the ZNode tree structure.
 */
public class ZKTree {
  private ZKClient zk = null;

  private String resetColor;
  private String matchColor;
  private String misMatchColor;

  /**
   * Create a ZKTree instance for traversal and query execution.
   * 
   * @param zk A ZooKeeper instance that provides access to the ZNode tree
   */
  public ZKTree(ZKClient zk) {
    this.zk = zk;
    this.resetColor = ZKPolicyDefs.Colors.valueOf("RESET").getANSIValue();
    this.matchColor = ZKPolicyDefs.Colors.valueOf(zk.getZKPConfig().getMatchColor()).getANSIValue();
    this.misMatchColor = ZKPolicyDefs.Colors.valueOf(zk.getZKPConfig().getMismatchColor()).getANSIValue();
  }

  /**
   * Function to return a tree view of the selected sub-tree and execute queries.
   *
   * @param rootPath      Path to start recursive query execution from
   * @param queryElements List of queries to be executed on each node
   * @param queriesOutput Output buffers for each query
   * @throws KeeperException
   * @throws InterruptedException
   * @throws SecurityException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws NoSuchFieldException
   */
  public void queryTree(String rootPath, List queryElements,
      Hashtable> queriesOutput)
      throws KeeperException, InterruptedException, NoSuchMethodException, SecurityException, IllegalAccessException,
      IllegalArgumentException, InvocationTargetException, NoSuchFieldException {

    List invalidQueries = new ArrayList();
    List parentYesChildNoQueries = new ArrayList();

    for (ZKQueryElement zkQueryElement : queryElements) {
      // validate root path requested:
      try {
        if (this.zk.exists(zkQueryElement.getRootPath(), null) == null) {
          queriesOutput.get(zkQueryElement.hashCode())
              .add("The path " + zkQueryElement.getRootPath() + " does not exist.");
          invalidQueries.add(zkQueryElement);
          continue;
        }
      } catch (IllegalArgumentException e) {
        queriesOutput.get(zkQueryElement.hashCode())
            .add("Invalid rootpath " + zkQueryElement.getRootPath() + " : " + e.getMessage());
        invalidQueries.add(zkQueryElement);
        continue;
      }
      if (zkQueryElement.getName().equals("parentYesChildNo")) {
        this.queryTreeIntParentYesChildNo(zkQueryElement.getRootPath(), "", "", null, true, false, false, queriesOutput,
            zkQueryElement);
        parentYesChildNoQueries.add(zkQueryElement);
      }

    }

    for (ZKQueryElement zkQueryElement : parentYesChildNoQueries) {
      queryElements.remove(zkQueryElement);
    }

    for (ZKQueryElement zkQueryElement : invalidQueries) {
      queryElements.remove(zkQueryElement);
    }

    if (queryElements.size() > 0) {
      this.queryTreeIntPreOrder(rootPath, "", "", queryElements, true, false, false, queriesOutput);
    }
  }

  /**
   * Recursive function that parses the full ZNode tree and executes queries on each step.
   * 
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws SecurityException
   * @throws NoSuchFieldException
   */
  private void queryTreeIntPreOrder(String path, String indent, String name, List queryElements,
      boolean isQueryRoot, boolean isLast, boolean isParentLast, Hashtable> queriesOutput)
      throws KeeperException, InterruptedException, NoSuchFieldException, SecurityException, IllegalArgumentException,
      IllegalAccessException {
    List children = null;
    try {
      children = this.zk.getChildren(path, null);
    } catch (NoAuthException e) {
      return;
    }

    List znodeACLList = this.zk.getACL(path, null);

    Boolean isQueryRootSentinel = true;
    // After we got the ACL, execute all the queries
    for (ZKQueryElement zkQueryElement : queryElements) {
      isQueryRootSentinel = false;
      String znodePrintColor = "";
      ZKQuery query = zkQueryElement.getQuery();

      if (query.query(znodeACLList, null, path, this.zk, zkQueryElement.getArgs())) {
        znodePrintColor = this.matchColor;
      } else {
        znodePrintColor = this.misMatchColor;
      }

      if (isQueryRoot) {
        name = path.substring(1, path.length());
      } else {
        if (indent.length() > 0) {
          if (isParentLast) {
            indent = indent.substring(0, indent.length() - ZKPolicyDefs.TerminalConstants.indentStepLength)
                + ZKPolicyDefs.TerminalConstants.lastParentIndent;
          } else {
            indent = indent.substring(0, indent.length() - ZKPolicyDefs.TerminalConstants.indentStepLength)
                + ZKPolicyDefs.TerminalConstants.innerParentIndent;
          }
        }
        if (isLast) {
          indent += ZKPolicyDefs.TerminalConstants.lastChildIndent;
        } else {
          indent += ZKPolicyDefs.TerminalConstants.innerChildIndent;
        }

      }
      queriesOutput.get(zkQueryElement.hashCode()).add(indent + znodePrintColor + "/" + name + this.resetColor);

    }

    if (path.equals("/")) {
      path = "";
    }
    Collections.sort(children);

    Iterator iterator = children.iterator();
    while (iterator.hasNext()) {
      String child = iterator.next();
      this.queryTreeIntPreOrder(path + "/" + child, indent, child, queryElements, isQueryRootSentinel,
          !iterator.hasNext(), isLast, queriesOutput);
    }
  }

  /**
   * Recursive function that constructs the full ZNode tree while passing parent
   * ACL to child queries.
   * 
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws SecurityException
   * @throws NoSuchFieldException
   */
  private void queryTreeIntParentYesChildNo(String path, String indent, String name, List parentACLList,
      boolean isQueryRoot, boolean isLast, boolean isParentLast, Hashtable> queriesOutput,
      ZKQueryElement queryElement) throws KeeperException, InterruptedException, NoSuchFieldException,
      SecurityException, IllegalArgumentException, IllegalAccessException {
    List children = null;

    try {
      children = this.zk.getChildren(path, null);
    } catch (NoAuthException e) {
      return;
    }

    String znodePrintColor = "";

    List znodeACLList = this.zk.getACL(path, null);

    ZKQuery query = queryElement.getQuery();

    if (parentACLList == null || query.query(znodeACLList, parentACLList, path, this.zk, null)) {
      znodePrintColor = this.matchColor;
    } else {
      znodePrintColor = this.misMatchColor;
    }
    parentACLList = this.zk.getACL(path, null);

    if (path.equals("/")) {
      path = "";
    } else if (isQueryRoot) {
      name = path.substring(1, path.length());
    } else {
      if (indent.length() > 0) {
        if (isParentLast) {
          indent = indent.substring(0, indent.length() - ZKPolicyDefs.TerminalConstants.indentStepLength)
              + ZKPolicyDefs.TerminalConstants.lastParentIndent;
        } else {
          indent = indent.substring(0, indent.length() - ZKPolicyDefs.TerminalConstants.indentStepLength)
              + ZKPolicyDefs.TerminalConstants.innerParentIndent;
        }
      }
      if (isLast) {
        indent += znodePrintColor + ZKPolicyDefs.TerminalConstants.lastChildIndent;
      } else {
        indent += znodePrintColor + ZKPolicyDefs.TerminalConstants.innerChildIndent;
      }
    }
    queriesOutput.get(queryElement.hashCode()).add(indent + this.resetColor + "/" + name);

    Collections.sort(children);

    Iterator iterator = children.iterator();
    while (iterator.hasNext()) {
      String child = iterator.next();
      this.queryTreeIntParentYesChildNo(path + "/" + child, indent, child, parentACLList, false, !iterator.hasNext(),
          isLast, queriesOutput, queryElement);
    }
  }

  /**
   * Function to return a list of the selected sub-tree with the full path of
   * query matching nodes.
   *
   * @param rootPath      Path to start recursive query execution from
   * @param queryElements List of queries to be executed on each node
   * @param queriesOutput Output buffers for each query
   * @throws KeeperException
   * @throws InterruptedException
   * @throws SecurityException
   * @throws NoSuchMethodException
   * @throws InvocationTargetException
   * @throws IllegalArgumentException
   * @throws IllegalAccessException
   * @throws NoSuchFieldException
   */
  public void queryFind(String rootPath, List queryElements,
      Hashtable> queriesOutput)
      throws KeeperException, InterruptedException, NoSuchMethodException, SecurityException, IllegalAccessException,
      IllegalArgumentException, InvocationTargetException, NoSuchFieldException {

    List invalidQueries = new ArrayList();
    List parentYesChildNoQueries = new ArrayList();
    for (ZKQueryElement zkQueryElement : queryElements) {
      // validate root path requested:
      try {
        if (this.zk.exists(zkQueryElement.getRootPath(), null) == null) {
          queriesOutput.get(zkQueryElement.hashCode())
              .add("The path " + zkQueryElement.getRootPath() + " does not exist.");
          invalidQueries.add(zkQueryElement);
          continue;
        }
      } catch (IllegalArgumentException e) {
        queriesOutput.get(zkQueryElement.hashCode())
            .add("Invalid rootpath " + zkQueryElement.getRootPath() + " : " + e.getMessage());
        invalidQueries.add(zkQueryElement);
        continue;
      }

      if (zkQueryElement.getName().equals("parentYesChildNo")) {
        this.queryFindIntParentYesChildNo(zkQueryElement.getRootPath(), null, queriesOutput, zkQueryElement);
        parentYesChildNoQueries.add(zkQueryElement);
      }
    }

    for (ZKQueryElement zkQueryElement : parentYesChildNoQueries) {
      queryElements.remove(zkQueryElement);
    }

    for (ZKQueryElement zkQueryElement : invalidQueries) {
      queryElements.remove(zkQueryElement);
    }

    if (queryElements.size() > 0) {
      this.queryFindIntPreOrder(rootPath, queryElements, queriesOutput);
    }
  }

  /**
   * Recursive function that constructs the full ZNode tree, executes queries
   *  and outputs lines matching each one of them.
   * 
   * @param queryElements List of queries to be executed on each node
   * @param queriesOutput Output buffers for each query
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws SecurityException
   * @throws NoSuchFieldException
   */
  private void queryFindIntPreOrder(String path, List queryElements,
      Hashtable> queriesOutput) throws KeeperException, InterruptedException,
      NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {

    List children = null;

    try {
      children = this.zk.getChildren(path, null);
    } catch (NoAuthException e) {
      for (ZKQueryElement zkQueryElement : queryElements) {
        queriesOutput.get(zkQueryElement.hashCode())
            .add("WARNING: No READ permission for " + path + ", skipping subtree");
      }
      return;
    }
    List znodeACLList = this.zk.getACL(path, null);

    for (ZKQueryElement zkQueryElement : queryElements) {
      ZKQuery query = zkQueryElement.getQuery();

      if (query.query(znodeACLList, null, path, this.zk, zkQueryElement.getArgs())) {
        queriesOutput.get(zkQueryElement.hashCode()).add(path);
      }
    }

    if (path.equals("/")) {
      path = "";
    }

    Collections.sort(children);
    for (String child : children) {
      this.queryFindIntPreOrder(path + "/" + child, queryElements, queriesOutput);
    }
  }

  /**
   * Recursive function that constructs the full ZNode tree, passing parent ACL to
   * children queries.
   * 
   * @throws IllegalAccessException
   * @throws IllegalArgumentException
   * @throws SecurityException
   * @throws NoSuchFieldException
   */
  private void queryFindIntParentYesChildNo(String path, List parentACLList,
      Hashtable> queriesOutput, ZKQueryElement queryElement) throws KeeperException,
      InterruptedException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {

    List children = null;

    try {
      children = this.zk.getChildren(path, null);
    } catch (NoAuthException e) {
      queriesOutput.get(queryElement.hashCode()).add("WARNING: No READ permission for " + path + ", skipping subtree");
      return;
    }
    List znodeACLList = this.zk.getACL(path, null);

    ZKQuery query = queryElement.getQuery();

    if (parentACLList != null && !query.query(znodeACLList, parentACLList, path, this.zk, null)) {
      queriesOutput.get(queryElement.hashCode()).add(path);
    }
    parentACLList = this.zk.getACL(path, null);

    if (path.equals("/")) {
      path = "";
    }

    Collections.sort(children);
    for (String child : children) {
      this.queryFindIntParentYesChildNo(path + "/" + child, parentACLList, queriesOutput, queryElement);
    }
  }

  /**
   * Return color code explanation for command line output.
   * 
   * @return Hint for colors used in tree representation
   */
  public String colorCodeExplanation() {
    String explanation = "";
    explanation += "* " + this.matchColor + this.zk.getZKPConfig().getMatchColor() + this.resetColor
        + ": znodes matching the query" + "\n";
    explanation += "* " + this.misMatchColor + this.zk.getZKPConfig().getMismatchColor() + this.resetColor
        + ": znodes not matching the query" + "\n";
    return explanation;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy