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.controller.sal.core.spi.data;
10 import java.util.Collection;
11 import java.util.List;
12 import org.eclipse.jdt.annotation.NonNull;
13 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
14 import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
15 import org.opendaylight.mdsal.dom.spi.AbstractRegistrationTree;
16 import org.opendaylight.mdsal.dom.spi.RegistrationTreeNode;
17 import org.opendaylight.mdsal.dom.spi.RegistrationTreeSnapshot;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
21 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * Abstract base class for {@link DOMStoreTreeChangePublisher} implementations.
29 public abstract class AbstractDOMStoreTreeChangePublisher
30 extends AbstractRegistrationTree<AbstractDOMDataTreeChangeListenerRegistration<?>>
31 implements DOMStoreTreeChangePublisher {
32 private static final Logger LOG = LoggerFactory.getLogger(AbstractDOMStoreTreeChangePublisher.class);
35 * Callback for subclass to notify specified registrations of a candidate at a specified path. This method is
36 * guaranteed to be only called from within {@link #processCandidateTree(DataTreeCandidate)}.
38 * @param registrations Registrations which are affected by the candidate node
39 * @param path Path of changed candidate node. Guaranteed to match the path specified by the registration
40 * @param node Candidate node
42 protected abstract void notifyListeners(@NonNull Collection<AbstractDOMDataTreeChangeListenerRegistration<?>>
43 registrations, @NonNull YangInstanceIdentifier path, @NonNull DataTreeCandidateNode node);
46 * Callback notifying the subclass that the specified registration is being closed and it's user no longer
47 * wishes to receive notifications. This notification is invoked while the
48 * {@link org.opendaylight.yangtools.concepts.ListenerRegistration#close()}
49 * method is executing. Subclasses can use this callback to properly remove any delayed notifications pending
50 * towards the registration.
52 * @param registration Registration which is being closed
54 protected abstract void registrationRemoved(@NonNull AbstractDOMDataTreeChangeListenerRegistration<?> registration);
57 * Process a candidate tree with respect to registered listeners.
59 * @param candidate candidate three which needs to be processed
61 protected final void processCandidateTree(final @NonNull DataTreeCandidate candidate) {
62 final DataTreeCandidateNode node = candidate.getRootNode();
63 if (node.getModificationType() == ModificationType.UNMODIFIED) {
64 LOG.debug("Skipping unmodified candidate {}", candidate);
68 try (RegistrationTreeSnapshot<AbstractDOMDataTreeChangeListenerRegistration<?>> snapshot = takeSnapshot()) {
69 lookupAndNotify(candidate.getRootPath().getPathArguments(), 0, snapshot.getRootNode(), candidate);
74 public final <L extends DOMDataTreeChangeListener> AbstractDOMDataTreeChangeListenerRegistration<L>
75 registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
76 // Take the write lock
79 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node =
80 findNodeFor(treeId.getPathArguments());
81 final AbstractDOMDataTreeChangeListenerRegistration<L> reg =
82 new AbstractDOMDataTreeChangeListenerRegistration<L>(listener) {
84 protected void removeRegistration() {
85 AbstractDOMStoreTreeChangePublisher.this.removeRegistration(node, this);
86 registrationRemoved(this);
90 addRegistration(node, reg);
93 // Always release the lock
98 private void lookupAndNotify(final List<PathArgument> args, final int offset,
99 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node,
100 final DataTreeCandidate candidate) {
101 if (args.size() != offset) {
102 final PathArgument arg = args.get(offset);
104 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> exactChild =
105 node.getExactChild(arg);
106 if (exactChild != null) {
107 lookupAndNotify(args, offset + 1, exactChild, candidate);
110 for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> c :
111 node.getInexactChildren(arg)) {
112 lookupAndNotify(args, offset + 1, c, candidate);
115 notifyNode(candidate.getRootPath(), node, candidate.getRootNode());
119 private void notifyNode(final YangInstanceIdentifier path,
120 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regNode,
121 final DataTreeCandidateNode candNode) {
122 if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
123 LOG.debug("Skipping unmodified candidate {}", path);
127 final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> regs = regNode.getRegistrations();
128 if (!regs.isEmpty()) {
129 notifyListeners(regs, path, candNode);
132 for (DataTreeCandidateNode candChild : candNode.getChildNodes()) {
133 if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
134 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regChild =
135 regNode.getExactChild(candChild.getIdentifier());
136 if (regChild != null) {
137 notifyNode(path.node(candChild.getIdentifier()), regChild, candChild);
140 for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> rc :
141 regNode.getInexactChildren(candChild.getIdentifier())) {
142 notifyNode(path.node(candChild.getIdentifier()), rc, candChild);