2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.dom.spi.store;
10 import com.google.common.collect.ImmutableList;
11 import java.util.Collection;
12 import java.util.List;
13 import javax.annotation.Nonnull;
14 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
15 import org.opendaylight.mdsal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
16 import org.opendaylight.mdsal.dom.spi.AbstractRegistrationTree;
17 import org.opendaylight.mdsal.dom.spi.RegistrationTreeNode;
18 import org.opendaylight.mdsal.dom.spi.RegistrationTreeSnapshot;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * Abstract base class for {@link DOMStoreTreeChangePublisher} implementations.
30 public abstract class AbstractDOMStoreTreeChangePublisher
31 extends AbstractRegistrationTree<AbstractDOMDataTreeChangeListenerRegistration<?>>
32 implements DOMStoreTreeChangePublisher {
33 private static final Logger LOG = LoggerFactory.getLogger(AbstractDOMStoreTreeChangePublisher.class);
36 * Callback for subclass to notify specified registrations
37 * of a candidate at a specified path. This method is guaranteed
38 * to be only called from within {@link #processCandidateTree(DataTreeCandidate)}.
39 * @param registrations Registrations which are affected by the candidate node
40 * @param path Path of changed candidate node. Guaranteed to match the path specified by the registration
41 * @param node Candidate node
43 protected abstract void notifyListeners(
44 @Nonnull Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations,
45 @Nonnull YangInstanceIdentifier path, @Nonnull DataTreeCandidateNode node);
48 * Callback notifying the subclass that the specified registration is being
49 * closed and it's user no longer
50 * wishes to receive notifications. This notification is invoked while
51 * the {@link org.opendaylight.yangtools.concepts.ListenerRegistration#close()}
52 * method is executing. Subclasses can use this callback to properly
53 * remove any delayed notifications pending
54 * towards the registration.
56 * @param registration Registration which is being closed
58 protected abstract void registrationRemoved(
59 @Nonnull AbstractDOMDataTreeChangeListenerRegistration<?> registration);
62 * Process a candidate tree with respect to registered listeners.
64 * @param candidate candidate three which needs to be processed
66 protected final void processCandidateTree(@Nonnull final DataTreeCandidate candidate) {
67 final DataTreeCandidateNode node = candidate.getRootNode();
68 if (node.getModificationType() == ModificationType.UNMODIFIED) {
69 LOG.debug("Skipping unmodified candidate {}", candidate);
73 try (final RegistrationTreeSnapshot<AbstractDOMDataTreeChangeListenerRegistration<?>> snapshot
75 final List<PathArgument> toLookup
76 = ImmutableList.copyOf(candidate.getRootPath().getPathArguments());
77 lookupAndNotify(toLookup, 0, snapshot.getRootNode(), candidate);
82 public <L extends DOMDataTreeChangeListener> AbstractDOMDataTreeChangeListenerRegistration<L>
83 registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
84 // Take the write lock
87 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node =
88 findNodeFor(treeId.getPathArguments());
89 final AbstractDOMDataTreeChangeListenerRegistration<L> reg =
90 new AbstractDOMDataTreeChangeListenerRegistration<L>(listener) {
92 protected void removeRegistration() {
93 AbstractDOMStoreTreeChangePublisher.this.removeRegistration(node, this);
94 registrationRemoved(this);
98 addRegistration(node, reg);
101 // Always release the lock
106 private void lookupAndNotify(final List<PathArgument> args,
107 final int offset, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node,
108 final DataTreeCandidate candidate) {
109 if (args.size() != offset) {
110 final PathArgument arg = args.get(offset);
112 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> exactChild
113 = node.getExactChild(arg);
114 if (exactChild != null) {
115 lookupAndNotify(args, offset + 1, exactChild, candidate);
118 for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> c :
119 node.getInexactChildren(arg)) {
120 lookupAndNotify(args, offset + 1, c, candidate);
123 notifyNode(candidate.getRootPath(), node, candidate.getRootNode());
127 private void notifyNode(final YangInstanceIdentifier path,
128 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regNode,
129 final DataTreeCandidateNode candNode) {
130 if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
131 LOG.debug("Skipping unmodified candidate {}", path);
135 final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> regs = regNode.getRegistrations();
136 if (!regs.isEmpty()) {
137 notifyListeners(regs, path, candNode);
140 for (DataTreeCandidateNode candChild : candNode.getChildNodes()) {
141 if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
142 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regChild =
143 regNode.getExactChild(candChild.getIdentifier());
144 if (regChild != null) {
145 notifyNode(path.node(candChild.getIdentifier()), regChild, candChild);
148 for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> rc :
149 regNode.getInexactChildren(candChild.getIdentifier())) {
150 notifyNode(path.node(candChild.getIdentifier()), rc, candChild);