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;
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;
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();
}
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;
}
};
- 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.
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;
* 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;
*
* @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);
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);
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);
}
}
-
}