Merge "Bug 1003: Restconf - remove whitespace on input"
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / tree / ListenerTree.java
index 58a0c69bb06a94e59d97f9dc88aee0ea71cef4ca..0d73143de2aad021ee17f7577d95eaabdc0af24e 100644 (file)
@@ -9,9 +9,9 @@ package org.opendaylight.controller.md.sal.dom.store.impl.tree;
 
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
@@ -21,6 +21,7 @@ import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
@@ -32,15 +33,24 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
+/**
+ * A set of listeners organized as a tree by node to which they listen. This class
+ * allows for efficient lookup of listeners when we walk the DataTreeCandidate.
+ */
 public final class ListenerTree {
     private static final Logger LOG = LoggerFactory.getLogger(ListenerTree.class);
     private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);
     private final Node rootNode = new Node(null, null);
 
     private ListenerTree() {
-
+        // Private to disallow direct instantiation
     }
 
+    /**
+     * Create a new empty instance of the listener tree.
+     *
+     * @return An empty instance.
+     */
     public static ListenerTree create() {
         return new ListenerTree();
     }
@@ -61,12 +71,12 @@ public final class ListenerTree {
 
         try {
             Node walkNode = rootNode;
-            for(PathArgument arg : path.getPath()) {
+            for (final PathArgument arg : path.getPath()) {
                 walkNode = walkNode.ensureChild(arg);
             }
 
             final Node node = walkNode;
-            DataChangeListenerRegistration<L> listenerReg = new DataChangeListenerRegistration<L>(listener) {
+            DataChangeListenerRegistration<L> reg = new DataChangeListenerRegistrationImpl<L>(listener) {
                 @Override
                 public DataChangeScope getScope() {
                     return scope;
@@ -101,14 +111,22 @@ public final class ListenerTree {
                 }
             };
 
-            node.addListener(listenerReg);
-            return listenerReg;
+            node.addListener(reg);
+            return reg;
         } finally {
             // Always release the lock
             rwLock.writeLock().unlock();
         }
     }
 
+    /**
+     * Obtain a tree walking context. This context ensures a consistent view of
+     * the listener registrations. The context should be closed as soon as it
+     * is not required, because each unclosed instance blocks modification of
+     * the listener tree.
+     *
+     * @return A walker instance.
+     */
     public Walker getWalker() {
         /*
          * TODO: The only current user of this method is local to the datastore.
@@ -123,6 +141,10 @@ public final class ListenerTree {
         return ret;
     }
 
+    /**
+     * A walking context, pretty much equivalent to an iterator, but it
+     * exposes the undelying tree structure.
+     */
     public static final class Walker implements AutoCloseable {
         private final Lock lock;
         private final Node node;
@@ -155,7 +177,7 @@ public final class ListenerTree {
      * unclosed.
      */
     public static final class Node implements StoreTreeNode<Node>, Identifiable<PathArgument> {
-        private final HashSet<DataChangeListenerRegistration<?>> listeners = new HashSet<>();
+        private final Collection<DataChangeListenerRegistration<?>> listeners = new ArrayList<>();
         private final Map<PathArgument, Node> children = new HashMap<>();
         private final PathArgument identifier;
         private final Reference<Node> parent;
@@ -182,13 +204,12 @@ public final class ListenerTree {
          *
          * @return the list of current listeners
          */
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        public Collection<org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<?>> getListeners() {
-            return (Collection) listeners;
+        public Collection<DataChangeListenerRegistration<?>> getListeners() {
+            return listeners;
         }
 
         private Node ensureChild(final PathArgument child) {
-            Node potential = (children.get(child));
+            Node potential = children.get(child);
             if (potential == null) {
                 potential = new Node(this, child);
                 children.put(child, potential);
@@ -201,7 +222,7 @@ public final class ListenerTree {
             LOG.debug("Listener {} registered", listener);
         }
 
-        private void removeListener(final DataChangeListenerRegistration<?> listener) {
+        private void removeListener(final DataChangeListenerRegistrationImpl<?> listener) {
             listeners.remove(listener);
             LOG.debug("Listener {} unregistered", listener);
 
@@ -220,14 +241,19 @@ public final class ListenerTree {
             children.remove(arg);
             removeThisIfUnused();
         }
-    }
 
-    private abstract static class DataChangeListenerRegistration<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractListenerRegistration<T> implements
-    org.opendaylight.controller.md.sal.dom.store.impl.DataChangeListenerRegistration<T> {
+        @Override
+        public String toString() {
+            return "Node [identifier=" + identifier + ", listeners=" + listeners.size() + ", children=" + children.size() + "]";
+        }
+
+
+    }
 
-        public DataChangeListenerRegistration(final T listener) {
+    private abstract static class DataChangeListenerRegistrationImpl<T extends AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> extends AbstractListenerRegistration<T> //
+    implements DataChangeListenerRegistration<T> {
+        public DataChangeListenerRegistrationImpl(final T listener) {
             super(listener);
         }
     }
-
 }