package edu.uw.zookeeper.data; import java.lang.ref.WeakReference; import java.util.AbstractMap; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ForwardingMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.UnmodifiableIterator; import edu.uw.zookeeper.common.AbstractPair; /** * Not threadsafe. */ public abstract class AbstractNameTrie<E extends NameTrie.Node<E>> implements NameTrie<E> { public static ZNodePath toPath(Object obj) { ZNodePath path; if (obj instanceof ZNodePath) { path = (ZNodePath) obj; } else { path = ZNodePath.fromString(obj.toString()); } return path; } public static <E extends Node<E>> ParentIterator<E> parentIterator(Pointer<? extends E> child) { return ParentIterator.from(child); } public static <E extends Node<E>> ZNodePath pathOf(Pointer<? extends E> pointer) { E parent = pointer.get(); if (parent == null) { return RootZNodePath.getInstance(); } else { return parent.path().join(pointer.name()); } } public static <E extends Node<E>> StrongPointer<E> rootPointer() { return StrongPointer.from(EmptyZNodeLabel.getInstance(), null); } public static <E extends Node<E>> StrongPointer<E> strongPointer(ZNodeName label, E node) { return StrongPointer.from(label, node); } public static <E extends Node<E>> WeakPointer<E> weakPointer(ZNodeName label, E node) { return WeakPointer.from(label, node); } public static <E extends Node<E>> PreOrderTraversal<E> preOrder(E node) { return new PreOrderTraversal<E>(node); } public static <E extends Node<E>> BreadthFirstTraversal<E> breadthFirst(E node) { return new BreadthFirstTraversal<E>(node); } public static class ParentIterator<E extends Node<E>> extends UnmodifiableIterator<Pointer<? extends E>> { public static <E extends Node<E>> ParentIterator<E> from(Pointer<? extends E> child) { return new ParentIterator<E>(StrongPointer.from(child.name(), child.get())); } protected Pointer<? extends E> next; protected ParentIterator(Pointer<? extends E> next) { this.next = next; } @Override public boolean hasNext() { return (next.get() != null); } @Override public Pointer<? extends E> next() { if (next.get() == null) { throw new NoSuchElementException(); } Pointer<? extends E> last = next; next = StrongPointer.from(last.get().parent().name(), last.get().parent().get()); return last; } } public static class StrongPointer<E extends Node<E>> extends AbstractPair<ZNodeName, E> implements Pointer<E> { public static <E extends Node<E>> StrongPointer<E> from(ZNodeName label, E node) { return new StrongPointer<E>(label, node); } public StrongPointer(ZNodeName label, E node) { super(label, node); } public ZNodeName name() { return first; } public E get() { return second; } @Override public String toString() { return MoreObjects.toStringHelper(this) .addValue(name()) .toString(); } } public static class WeakPointer<E extends Node<E>> extends AbstractPair<ZNodeName, WeakReference<E>> implements Pointer<E> { public static <E extends Node<E>> WeakPointer<E> from(ZNodeName label, E node) { return new WeakPointer<E>(label, node); } public WeakPointer(ZNodeName label, E node) { super(label, new WeakReference<E>(node)); } public ZNodeName name() { return first; } public E get() { return second.get(); } @Override public String toString() { return MoreObjects.toStringHelper(this) .addValue(name()) .toString(); } } public static enum TraversalStrategy { PREORDER, BREADTH_FIRST; } public static abstract class IterativeTraversal<E extends Node<E>> implements Iterator<E> { protected E last; protected final LinkedList<E> pending; protected IterativeTraversal(E root) { this.last = null; this.pending = Lists.newLinkedList(); pending.add(root); } public abstract TraversalStrategy strategy(); @Override public boolean hasNext() { return !pending.isEmpty(); } @Override public E next() { last = dequeue(); for (E child: childrenOf(last)) { enqueue(child); } return last; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public String toString() { return MoreObjects.toStringHelper(this).add("strategy", strategy()).add("last", last).add("pending", pending).toString(); } protected Iterable<E> childrenOf(E node) { return node.values(); } /** * @return next node * @throws NoSuchElementException */ protected abstract E dequeue(); protected abstract void enqueue(E node); } public static class PreOrderTraversal<E extends Node<E>> extends IterativeTraversal<E> { public PreOrderTraversal(E root) { super(root); } @Override public TraversalStrategy strategy() { return TraversalStrategy.PREORDER; } @Override protected E dequeue() { return pending.pop(); } @Override protected void enqueue(E node) { pending.push(node); } } public static class BreadthFirstTraversal<E extends Node<E>> extends IterativeTraversal<E> { public BreadthFirstTraversal(E root) { super(root); } @Override public TraversalStrategy strategy() { return TraversalStrategy.BREADTH_FIRST; } @Override protected E dequeue() { return pending.remove(); } @Override protected void enqueue(E node) { pending.add(node); } } public static abstract class SimpleNode<E extends SimpleNode<E>> extends ForwardingMap<ZNodeName, E> implements Node<E> { public static ZNodeName toName(Object obj) { ZNodeName name; if (obj instanceof ZNodeName) { name = (ZNodeName) obj; } else { name = ZNodeName.fromString(obj.toString()); } return name; } private final Pointer<? extends E> parent; private final Map<ZNodeName, E> children; private final ZNodePath path; protected SimpleNode( Pointer<? extends E> parent) { this(parent, Maps.<ZNodeName, E>newHashMap()); } protected SimpleNode( Pointer<? extends E> parent, Map<ZNodeName, E> children) { this(pathOf(parent), parent, children); } protected SimpleNode( ZNodePath path, Pointer<? extends E> parent, Map<ZNodeName, E> children) { this.parent = parent; this.children = children; this.path = path; } public boolean remove() { E parent = parent().get(); if (parent != null) { if (this == parent.get(parent().name())) { E child = parent.remove(parent().name()); assert(child == this); return true; } } return false; } @Override public ZNodePath path() { return path; } @Override public Pointer<? extends E> parent() { return parent; } @Override public boolean containsKey(Object key) { return children.containsKey(toName(key)); } @Override public E get(Object k) { return children.get(toName(k)); } @Override public E remove(Object k) { return children.remove(toName(k)); } @Override public String toString() { return toString(MoreObjects.toStringHelper(this)).toString(); } protected MoreObjects.ToStringHelper toString(MoreObjects.ToStringHelper toString) { return toString .add("path", path()) .add("children", keySet()); } @Override protected Map<ZNodeName, E> delegate() { return children; } } private final E root; protected AbstractNameTrie(E root) { this.root = root; } public E root() { return root; } @Override public void clear() { // assume we use weak pointers for parent pointers root.clear(); } @Override public boolean containsKey(Object k) { return get(k) != null; } @Override public boolean containsValue(Object v) { @SuppressWarnings("unchecked") E item = get(((E) v).path()); return Objects.equal(v, item); } @Override public Set<Map.Entry<ZNodePath, E>> entrySet() { ImmutableSet.Builder<Map.Entry<ZNodePath, E>> entries = ImmutableSet.builder(); for (E e: this) { entries.add(new AbstractMap.SimpleImmutableEntry<ZNodePath, E>(e.path(), e)); } return entries.build(); } @Override public boolean isEmpty() { return root.isEmpty(); } @Override public Set<ZNodePath> keySet() { ImmutableSet.Builder<ZNodePath> keys = ImmutableSet.builder(); for (E e: this) { keys.add(e.path()); } return keys.build(); } @Override public void putAll(Map<? extends ZNodePath, ? extends E> m) { for (Map.Entry<? extends ZNodePath, ? extends E> e: m.entrySet()) { put(e.getKey(), e.getValue()); } } @Override public int size() { return values().size(); } @Override public Collection<E> values() { return ImmutableList.copyOf(this); } @Override public Iterator<E> iterator() { return preOrder(root); } @Override public String toString() { return Iterables.toString(this); } }