Merge "BUG 3045 : Use non-strict parsing in hello message."
[controller.git] / opendaylight / md-sal / sal-dom-spi / src / main / java / org / opendaylight / controller / sal / core / spi / data / AbstractDOMStoreTreeChangePublisher.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.core.spi.data;
9
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.controller.md.sal.dom.api.DOMDataTreeChangeListener;
15 import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
16 import org.opendaylight.controller.md.sal.dom.spi.AbstractRegistrationTree;
17 import org.opendaylight.controller.md.sal.dom.spi.RegistrationTreeNode;
18 import org.opendaylight.controller.md.sal.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;
26
27 /**
28  * Abstract base class for {@link DOMStoreTreeChangePublisher} implementations.
29  */
30 public abstract class AbstractDOMStoreTreeChangePublisher extends AbstractRegistrationTree<AbstractDOMDataTreeChangeListenerRegistration<?>> implements DOMStoreTreeChangePublisher {
31     private static final Logger LOG = LoggerFactory.getLogger(AbstractDOMStoreTreeChangePublisher.class);
32
33     /**
34      * Callback for subclass to notify specified registrations of a candidate at a specified path. This method is guaranteed
35      * to be only called from within {@link #processCandidateTree(DataTreeCandidate)}.
36      *
37      * @param registrations Registrations which are affected by the candidate node
38      * @param path Path of changed candidate node. Guaranteed to match the path specified by the registration
39      * @param node Candidate node
40      */
41     protected abstract void notifyListeners(@Nonnull Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations, @Nonnull YangInstanceIdentifier path, @Nonnull DataTreeCandidateNode node);
42
43     /**
44      * Callback notifying the subclass that the specified registration is being closed and it's user no longer
45      * wishes to receive notifications. This notification is invoked while the {@link org.opendaylight.yangtools.concepts.ListenerRegistration#close()}
46      * method is executing. Subclasses can use this callback to properly remove any delayed notifications pending
47      * towards the registration.
48      *
49      * @param registration Registration which is being closed
50      */
51     protected abstract void registrationRemoved(@Nonnull AbstractDOMDataTreeChangeListenerRegistration<?> registration);
52
53     /**
54      * Process a candidate tree with respect to registered listeners.
55      *
56      * @param candidate candidate three which needs to be processed
57      */
58     protected final void processCandidateTree(@Nonnull final DataTreeCandidate candidate) {
59         final DataTreeCandidateNode node = candidate.getRootNode();
60         if (node.getModificationType() == ModificationType.UNMODIFIED) {
61             LOG.debug("Skipping unmodified candidate {}", candidate);
62             return;
63         }
64
65         try (final RegistrationTreeSnapshot<AbstractDOMDataTreeChangeListenerRegistration<?>> snapshot = takeSnapshot()) {
66             final List<PathArgument> toLookup = ImmutableList.copyOf(candidate.getRootPath().getPathArguments());
67             lookupAndNotify(toLookup, 0, snapshot.getRootNode(), candidate);
68         }
69     }
70
71     @Override
72     public final <L extends DOMDataTreeChangeListener> AbstractDOMDataTreeChangeListenerRegistration<L> registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
73         // Take the write lock
74         takeLock();
75         try {
76             final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node = findNodeFor(treeId.getPathArguments());
77             final AbstractDOMDataTreeChangeListenerRegistration<L> reg = new AbstractDOMDataTreeChangeListenerRegistration<L>(listener) {
78                 @Override
79                 protected void removeRegistration() {
80                     AbstractDOMStoreTreeChangePublisher.this.removeRegistration(node, this);
81                     registrationRemoved(this);
82                 }
83             };
84
85             addRegistration(node, reg);
86             return reg;
87         } finally {
88             // Always release the lock
89             releaseLock();
90         }
91     }
92
93     private void lookupAndNotify(final List<PathArgument> args, final int offset, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> node, final DataTreeCandidate candidate) {
94         if (args.size() != offset) {
95             final PathArgument arg = args.get(offset);
96
97             final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> exactChild = node.getExactChild(arg);
98             if (exactChild != null) {
99                 lookupAndNotify(args, offset + 1, exactChild, candidate);
100             }
101
102             for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> c : node.getInexactChildren(arg)) {
103                 lookupAndNotify(args, offset + 1, c, candidate);
104             }
105         } else {
106             notifyNode(candidate.getRootPath(), node, candidate.getRootNode());
107         }
108     }
109
110     private void notifyNode(final YangInstanceIdentifier path, final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regNode, final DataTreeCandidateNode candNode) {
111         if (candNode.getModificationType() == ModificationType.UNMODIFIED) {
112             LOG.debug("Skipping unmodified candidate {}", path);
113             return;
114         }
115
116         final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> regs = regNode.getRegistrations();
117         if (!regs.isEmpty()) {
118             notifyListeners(regs, path, candNode);
119         }
120
121         for (DataTreeCandidateNode candChild : candNode.getChildNodes()) {
122             if (candChild.getModificationType() != ModificationType.UNMODIFIED) {
123                 final RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> regChild = regNode.getExactChild(candChild.getIdentifier());
124                 if (regChild != null) {
125                     notifyNode(path.node(candChild.getIdentifier()), regChild, candChild);
126                 }
127
128                 for (RegistrationTreeNode<AbstractDOMDataTreeChangeListenerRegistration<?>> rc : regNode.getInexactChildren(candChild.getIdentifier())) {
129                     notifyNode(path.node(candChild.getIdentifier()), rc, candChild);
130                 }
131             }
132         }
133     }
134 }