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

com.google.security.fences.namespace.NamespaceTrie Maven / Gradle / Ivy

Go to download

Augments Java's access control by checking that a Maven Project and all its dependencies conform to a policy that specifies which classes/packages can link to which others.

There is a newer version: 1.9-beta
Show newest version
package com.google.security.fences.namespace;

import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;

/**
 * Maps package and class names to values.
 *
 * @param  The value type stored at a Trie node.
 * @param  The type that can be added to a Trie node.
 *    This can be a part of the COMPLEX_VALUE allowing the trie to easily
 *    function as a MultiTrie.
 */
public final class NamespaceTrie {
  final Entry root = new Entry(null);
  final Supplier makeEmpty;
  final Function> folder;

  /**
   * @param makeEmpty a supplier for empty complex values.
   * @param folder combines a previous complex value and a simple value being
   *    added to a node together to produce the new complex value.
   */
  public NamespaceTrie(
      Supplier makeEmpty,
      Function> folder) {
    this.makeEmpty = makeEmpty;
    this.folder = folder;
  }

  /** The minimal collection of entries that includes all overlapping ns. */
  public Map overlapping(Namespace ns) {
    Entry e = getEntry(ns, false, false);
    ImmutableMap.Builder b =
        ImmutableMap.builder();
    if (e != null) {
      e.addTransitively(ns, b);
    }
    return b.build();
  }

  /**
   * The node specified by the given namespace if any.
   */
  public Entry get(Namespace ns) {
    return getEntry(ns, false, false);
  }

  /**
   * Folds a simple value into the node specified by ns,
   * creating a new node if necessary.
   */
  public Entry put(Namespace ns, SIMPLE_VALUE simpleValue) {
    Entry e = Preconditions.checkNotNull(
        getEntry(ns, true, false));
    e.putValue(this.makeEmpty, this.folder, simpleValue);
    return e;
  }

  /**
   * The value at namespace or one of its ancestors giving preferences to
   * deeper nodes.
   */
  public Entry getDeepest(Namespace ns) {
    return getEntry(ns, false, true);
  }

  private Entry getEntry(
      Namespace ns, boolean manufacture, boolean bestEffort) {
    Entry parentEntry;
    Optional parent = ns.getParent();
    if (parent.isPresent()) {
      parentEntry = getEntry(parent.get(), manufacture, bestEffort);
      if (parentEntry == null) { return null; }
    } else {
      parentEntry = root;
    }
    Optional nameOpt = ns.getName();
    if (nameOpt.isPresent()) {
      String name = nameOpt.get();
      @SuppressWarnings("synthetic-access")
      SortedMap> children = parentEntry.children;
      Entry child = children.get(name);
      if (child == null) {
        if (manufacture) {
          child = new Entry(parentEntry);
          children.put(name, child);
        } else if (bestEffort) {
          return parentEntry;
        }
      }
      return child;
    } else {
      return parentEntry;
    }
  }

  /**
   * A diagnostic text representation of the trie with one line per entry.
   */
  public String toTree() {
    return root.toTree();
  }


  /** A trie entry. */
  public static final class Entry {
    private Optional value = Optional.absent();
    private final Entry parent;
    private final SortedMap> children =
        new TreeMap>();

    Entry(Entry parent) {
      this.parent = parent;
    }

    
    void putValue(
        Supplier emptyValue, Function> fold,
        X newValuePart) {
      T newValue = fold.apply(value.or(emptyValue)).apply(newValuePart);
      value = Optional.of(newValue);
    }

    /** The value if any is specified. */
    public Optional getValue() {
      return value;
    }

    /** The parent entry or absent if this entry is the root of the trie. */
    public Optional> getParent() {
      return Optional.fromNullable(parent);
    }

    void addTransitively(Namespace ns, ImmutableMap.Builder out) {
      if (value.isPresent()) {
        out.put(ns, value.get());
      }
      for (Map.Entry> e : children.entrySet()) {
        e.getValue().addTransitively(ns.child(e.getKey()), out);
      }
    }

    @Override
    public String toString() {
      return toShallowString();
    }

    String toShallowString() {
      return "Entry " + value;
    }

    /** A diagnostic string containing the entry in indented tree form. */
    public String toTree() {
      StringBuilder sb = new StringBuilder();
      toTree(sb, 0);
      return sb.toString();
    }

    /**
     * Appends a diagnostic string containing the entry in indented tree form.
     *
     * @param sb receives the text of the tree
     * @param n the indentation level.
     */
    public void toTree(StringBuilder sb, int n) {
      sb.append(toShallowString());
      int childDepth = n + 1;
      for (Map.Entry> e : children.entrySet()) {
        sb.append('\n');
        for (int i = childDepth; --i >= 0;) { sb.append(". "); }
        sb.append(e.getKey()).append(" => ");
        e.getValue().toTree(sb, childDepth);
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy