X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-inmemory-datastore%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2Ftree%2FListenerTree.java;h=c0ad313291892b8873ee903b7de80def2f310bb5;hp=9d04a1b6ed039043a7737699b4c3bf88a5a91ef7;hb=f4218f246f06a88f16588e61eea3ed99009ee66d;hpb=7e24111a0842d66187c752022aa975c411b42cca diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java index 9d04a1b6ed..c0ad313291 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java @@ -7,42 +7,21 @@ */ package org.opendaylight.controller.md.sal.dom.store.impl.tree; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - -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.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -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.spi.AbstractRegistrationTree; +import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode; 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 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.api.schema.tree.StoreTreeNode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * 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. + * + * @author Robert Varga */ -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); - +public final class ListenerTree extends AbstractRegistrationTree> { private ListenerTree() { // Private to disallow direct instantiation } @@ -64,19 +43,13 @@ public final class ListenerTree { * @param scope Scope of triggering event. * @return Listener registration */ - public >> DataChangeListenerRegistration registerDataChangeListener(final InstanceIdentifier path, + public >> DataChangeListenerRegistration registerDataChangeListener(final YangInstanceIdentifier path, final L listener, final DataChangeScope scope) { // Take the write lock - rwLock.writeLock().lock(); - + takeLock(); try { - Node walkNode = rootNode; - for (final PathArgument arg : path.getPathArguments()) { - walkNode = walkNode.ensureChild(arg); - } - - final Node node = walkNode; + final RegistrationTreeNode> node = findNodeFor(path.getPathArguments()); DataChangeListenerRegistration reg = new DataChangeListenerRegistrationImpl(listener) { @Override public DataChangeScope getScope() { @@ -84,7 +57,7 @@ public final class ListenerTree { } @Override - public InstanceIdentifier getPath() { + public YangInstanceIdentifier getPath() { return path; } @@ -100,23 +73,15 @@ public final class ListenerTree { * While this does not directly violate the ListenerRegistration * contract, it is probably not going to be liked by the users. */ - - // Take the write lock - ListenerTree.this.rwLock.writeLock().lock(); - try { - node.removeListener(this); - } finally { - // Always release the lock - ListenerTree.this.rwLock.writeLock().unlock(); - } + ListenerTree.this.removeRegistration(node, this); } }; - node.addListener(reg); + addRegistration(node, reg); return reg; } finally { // Always release the lock - rwLock.writeLock().unlock(); + releaseLock(); } } @@ -127,8 +92,11 @@ public final class ListenerTree { * the listener tree. * * @return A walker instance. + * + * @deprecated Use {@link #takeSnapshot()} instead. */ - public Walker getWalker() { + @Deprecated + public ListenerWalker getWalker() { /* * TODO: The only current user of this method is local to the datastore. * Since this class represents a read-lock, losing a reference to @@ -137,124 +105,6 @@ public final class ListenerTree { * external user exist, make the Walker a phantom reference, which * will cleanup the lock if not told to do so. */ - final Walker ret = new Walker(rwLock.readLock(), rootNode); - rwLock.readLock().lock(); - 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; - - @GuardedBy("this") - private boolean valid = true; - - private Walker(final Lock lock, final Node node) { - this.lock = Preconditions.checkNotNull(lock); - this.node = Preconditions.checkNotNull(node); - } - - public Node getRootNode() { - return node; - } - - @Override - public synchronized void close() { - if (valid) { - lock.unlock(); - valid = false; - } - } - } - - /** - * This is a single node within the listener tree. Note that the data returned from - * and instance of this class is guaranteed to have any relevance or consistency - * only as long as the {@link org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker} instance through which it is reached remains - * unclosed. - */ - public static final class Node implements StoreTreeNode, Identifiable { - private final Collection> listeners = new ArrayList<>(); - private final Map children = new HashMap<>(); - private final PathArgument identifier; - private final Reference parent; - - private Node(final Node parent, final PathArgument identifier) { - this.parent = new WeakReference<>(parent); - this.identifier = identifier; - } - - @Override - public PathArgument getIdentifier() { - return identifier; - } - - @Override - public Optional getChild(final PathArgument child) { - return Optional.fromNullable(children.get(child)); - } - - /** - * Return the list of current listeners. This collection is guaranteed - * to be immutable only while the walker, through which this node is - * reachable remains unclosed. - * - * @return the list of current listeners - */ - public Collection> getListeners() { - return listeners; - } - - private Node ensureChild(final PathArgument child) { - Node potential = children.get(child); - if (potential == null) { - potential = new Node(this, child); - children.put(child, potential); - } - return potential; - } - - private void addListener(final DataChangeListenerRegistration listener) { - listeners.add(listener); - LOG.debug("Listener {} registered", listener); - } - - private void removeListener(final DataChangeListenerRegistrationImpl listener) { - listeners.remove(listener); - LOG.debug("Listener {} unregistered", listener); - - // We have been called with the write-lock held, so we can perform some cleanup. - removeThisIfUnused(); - } - - private void removeThisIfUnused() { - final Node p = parent.get(); - if (p != null && listeners.isEmpty() && children.isEmpty()) { - p.removeChild(identifier); - } - } - - private void removeChild(final PathArgument arg) { - children.remove(arg); - removeThisIfUnused(); - } - - @Override - public String toString() { - return "Node [identifier=" + identifier + ", listeners=" + listeners.size() + ", children=" + children.size() + "]"; - } - - - } - - private abstract static class DataChangeListenerRegistrationImpl>> extends AbstractListenerRegistration // - implements DataChangeListenerRegistration { - public DataChangeListenerRegistrationImpl(final T listener) { - super(listener); - } + return new ListenerWalker(takeSnapshot()); } }