2 * Copyright (c) 2014 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.store.inmemory;
10 import java.util.List;
11 import java.util.concurrent.Executor;
12 import org.eclipse.jdt.annotation.NonNull;
13 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
14 import org.opendaylight.mdsal.dom.spi.store.AbstractDOMStoreTreeChangePublisher;
15 import org.opendaylight.yangtools.concepts.Registration;
16 import org.opendaylight.yangtools.util.concurrent.EqualityQueuedNotificationManager;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
19 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeCandidate;
20 import org.opendaylight.yangtools.yang.data.tree.api.DataTreeSnapshot;
21 import org.opendaylight.yangtools.yang.data.tree.spi.DataTreeCandidates;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
25 final class InMemoryDOMStoreTreeChangePublisher extends AbstractDOMStoreTreeChangePublisher {
26 private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMStoreTreeChangePublisher.class);
28 // Registrations use identity for equality, hence we can skip wrapping them
29 private final EqualityQueuedNotificationManager<Reg, DataTreeCandidate> notificationManager;
31 InMemoryDOMStoreTreeChangePublisher(final String dsName, final Executor listenerExecutor, final int maxQueueSize) {
32 notificationManager = new EqualityQueuedNotificationManager<>("DataTreeChangeListenerQueueMgr + dsName",
33 listenerExecutor, maxQueueSize,
34 (listener, notifications) -> {
35 if (listener.notClosed()) {
36 listener.listener().onDataTreeChanged(notifications);
41 private InMemoryDOMStoreTreeChangePublisher(
42 final EqualityQueuedNotificationManager<Reg, DataTreeCandidate> notificationManager) {
43 this.notificationManager = notificationManager;
46 EqualityQueuedNotificationManager<?, ?> getNotificationManager() {
47 return notificationManager;
51 protected void notifyListener(final Reg registration, final List<DataTreeCandidate> changes) {
52 LOG.debug("Enqueueing candidates {} for registration {}", changes, registration);
53 notificationManager.submitNotifications(registration, changes);
57 protected synchronized void registrationRemoved(final Reg registration) {
58 LOG.debug("Closing registration {}", registration);
60 // FIXME: remove the queue for this registration and make sure we clear it
63 Registration registerTreeChangeListener(final YangInstanceIdentifier treeId,
64 final DOMDataTreeChangeListener listener, final DataTreeSnapshot snapshot) {
65 final var reg = registerTreeChangeListener(treeId, listener);
66 final var preExistingData = snapshot.readNode(YangInstanceIdentifier.of());
67 if (preExistingData.isEmpty()) {
68 listener.onInitialData();
72 final var data = preExistingData.orElseThrow();
73 if (treeId.isEmpty()) {
74 if (data instanceof DataContainerNode container) {
75 if (container.isEmpty()) {
76 // If we are listening on root of data tree we still get empty normalized node, root is always
77 // present, we should filter this out separately and notify it by 'onInitialData()' once.
78 // Otherwise, it is just a valid data node with empty value which also should be notified by
79 // "onDataTreeChanged(List<DataTreeCandidate>)".
80 listener.onInitialData();
84 throw new IllegalStateException("Unexpected root node type " + data.contract());
88 final var candidate = DataTreeCandidates.fromNormalizedNode(YangInstanceIdentifier.of(), data);
89 final var publisher = new InMemoryDOMStoreTreeChangePublisher(notificationManager);
90 publisher.registerTreeChangeListener(treeId, listener);
91 if (!publisher.publishChange(candidate)) {
92 // There is no data in the conceptual data tree then notify with 'onInitialData()'.
93 listener.onInitialData();
99 synchronized boolean publishChange(final @NonNull DataTreeCandidate candidate) {
100 // Runs synchronized with registrationRemoved()
101 return processCandidateTree(candidate);