package org.opendaylight.controller.cluster.datastore;
import java.util.Collection;
-import java.util.Collections;
import javax.annotation.concurrent.NotThreadSafe;
-import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
-import org.opendaylight.controller.sal.core.spi.data.AbstractDOMStoreTreeChangePublisher;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.mdsal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration;
+import org.opendaylight.mdsal.dom.spi.store.AbstractDOMStoreTreeChangePublisher;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
}
@Override
- protected void notifyListeners(final Collection<AbstractDOMDataTreeChangeListenerRegistration<?>> registrations,
- final YangInstanceIdentifier path, final DataTreeCandidateNode node) {
- final Collection<DataTreeCandidate> changes = Collections.<DataTreeCandidate>singleton(
- DataTreeCandidates.newDataTreeCandidate(path, node));
-
- for (AbstractDOMDataTreeChangeListenerRegistration<?> reg : registrations) {
- reg.getInstance().onDataTreeChanged(changes);
- }
+ protected void notifyListener(AbstractDOMDataTreeChangeListenerRegistration<?> registration,
+ Collection<DataTreeCandidate> changes) {
+ registration.getInstance().onDataTreeChanged(changes);
}
@Override
protected void registrationRemoved(final AbstractDOMDataTreeChangeListenerRegistration<?> registration) {
LOG.debug("Registration {} removed", registration);
}
+
+ @Override
+ public <L extends org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener> ListenerRegistration<L>
+ registerTreeChangeListener(final YangInstanceIdentifier treeId, final L listener) {
+ final AbstractDOMDataTreeChangeListenerRegistration<DOMDataTreeChangeListener> registration =
+ super.registerTreeChangeListener(treeId, (org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener)
+ changes -> listener.onDataTreeChanged(changes));
+
+ return new org.opendaylight.controller.md.sal.dom.spi.AbstractDOMDataTreeChangeListenerRegistration<L>(
+ listener) {
+ @Override
+ protected void removeRegistration() {
+ registration.close();
+ }
+ };
+ }
}
import static org.opendaylight.controller.md.cluster.datastore.model.TestModel.testNodeWithOuter;
import akka.actor.ActorRef;
+import akka.actor.ActorSelection;
+import akka.pattern.Patterns;
+import akka.testkit.JavaTestKit;
import akka.testkit.TestActorRef;
+import akka.util.Timeout;
+import com.google.common.base.Throwables;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeChangeListenerRegistration;
+import org.opendaylight.controller.cluster.datastore.messages.CloseDataTreeChangeListenerRegistrationReply;
import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListener;
+import org.opendaylight.controller.cluster.datastore.messages.RegisterDataTreeChangeListenerReply;
import org.opendaylight.controller.cluster.datastore.utils.MockDataTreeChangeListener;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import scala.concurrent.Await;
+import scala.concurrent.duration.Duration;
/**
* Unit tests for DataTreeChangeListenerSupport.
*/
public class DataTreeChangeListenerSupportTest extends AbstractShardTest {
private Shard shard;
- private DataTreeChangeListenerSupport support;
+ private TestActorRef<Shard> shardActor;
+ @Override
@Before
- public void setup() {
- shard = createShard();
- support = new DataTreeChangeListenerSupport(shard);
+ public void setUp() {
+ super.setUp();
+ createShard();
}
@Override
@Test
public void testChangeListenerWithNoInitialData() throws Exception {
- MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0, true);
+ MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 0).getKey();
listener.expectNoMoreChanges("Unexpected initial change event");
}
public void testInitialChangeListenerEventWithContainerPath() throws Exception {
writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
- MockDataTreeChangeListener listener = registerChangeListener(TEST_PATH, 1, true);
+ Entry<MockDataTreeChangeListener, ActorSelection> entry = registerChangeListener(TEST_PATH, 1);
+ MockDataTreeChangeListener listener = entry.getKey();
listener.waitForChangeEvents();
listener.verifyNotifiedData(TEST_PATH);
+
+ listener.reset(1);
+
+ writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
+ listener.waitForChangeEvents();
+ listener.verifyNotifiedData(TEST_PATH);
+
+ listener.reset(1);
+ JavaTestKit kit = new JavaTestKit(getSystem());
+ entry.getValue().tell(CloseDataTreeChangeListenerRegistration.getInstance(), kit.getRef());
+ kit.expectMsgClass(JavaTestKit.duration("5 seconds"), CloseDataTreeChangeListenerRegistrationReply.class);
+
+ writeToStore(shard.getDataStore(), TEST_PATH, ImmutableNodes.containerNode(TEST_QNAME));
+ listener.verifyNoNotifiedData(TEST_PATH);
}
@Test
public void testInitialChangeListenerEventWithListPath() throws Exception {
mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
- MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1, true);
+ MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH, 1).getKey();
listener.waitForChangeEvents();
listener.verifyNotifiedData(OUTER_LIST_PATH);
public void testInitialChangeListenerEventWithWildcardedListPath() throws Exception {
mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(1, 2));
- MockDataTreeChangeListener listener = registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 2, true);
+ MockDataTreeChangeListener listener =
+ registerChangeListener(OUTER_LIST_PATH.node(OUTER_LIST_QNAME), 1).getKey();
listener.waitForChangeEvents();
listener.verifyNotifiedData(outerEntryPath(1), outerEntryPath(2));
outerNodeEntry(1, innerNode("one", "two")), outerNodeEntry(2, innerNode("three", "four")))));
MockDataTreeChangeListener listener = registerChangeListener(
- OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 4, true);
+ OUTER_LIST_PATH.node(OUTER_LIST_QNAME).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
listener.waitForChangeEvents();
listener.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"), innerEntryPath(2, "three"),
// Register for a specific outer list entry
MockDataTreeChangeListener listener2 = registerChangeListener(
- OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 2, true);
+ OUTER_LIST_PATH.node(outerEntryKey(1)).node(INNER_LIST_QNAME).node(INNER_LIST_QNAME), 1).getKey();
listener2.waitForChangeEvents();
listener2.verifyNotifiedData(innerEntryPath(1, "one"), innerEntryPath(1, "two"));
listener2.verifyNoNotifiedData(innerEntryPath(2, "three"), innerEntryPath(2, "four"));
+
+ listener.reset(1);
+ listener2.reset(1);
+
+ mergeToStore(shard.getDataStore(), TEST_PATH, testNodeWithOuter(outerNode(
+ outerNodeEntry(1, innerNode("three")))));
+
+ listener.waitForChangeEvents();
+ listener.verifyNotifiedData(innerEntryPath(1, "three"));
+
+ listener2.waitForChangeEvents();
+ listener2.verifyNotifiedData(innerEntryPath(1, "three"));
}
- private MockDataTreeChangeListener registerChangeListener(final YangInstanceIdentifier path,
- final int expectedEvents, final boolean isLeader) {
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private Entry<MockDataTreeChangeListener, ActorSelection> registerChangeListener(final YangInstanceIdentifier path,
+ final int expectedEvents) {
MockDataTreeChangeListener listener = new MockDataTreeChangeListener(expectedEvents);
ActorRef dclActor = actorFactory.createActor(DataTreeChangeListenerActor.props(listener));
- support.onMessage(new RegisterDataTreeChangeListener(path, dclActor, false), isLeader, true);
- return listener;
+
+ try {
+ RegisterDataTreeChangeListenerReply reply = (RegisterDataTreeChangeListenerReply)
+ Await.result(Patterns.ask(shardActor, new RegisterDataTreeChangeListener(path, dclActor, false),
+ new Timeout(5, TimeUnit.SECONDS)), Duration.create(5, TimeUnit.SECONDS));
+ return new SimpleEntry<>(listener, getSystem().actorSelection(reply.getListenerRegistrationPath()));
+
+ } catch (Exception e) {
+ Throwables.propagate(e);
+ return null;
+ }
}
- private Shard createShard() {
- TestActorRef<Shard> actor = actorFactory.createTestActor(newShardProps());
- ShardTestKit.waitUntilLeader(actor);
- return actor.underlyingActor();
+ private void createShard() {
+ shardActor = actorFactory.createTestActor(newShardProps());
+ ShardTestKit.waitUntilLeader(shardActor);
+ shard = shardActor.underlyingActor();
}
}
public class MockDataTreeChangeListener implements DOMDataTreeChangeListener {
- private final List<Collection<DataTreeCandidate>> changeList =
- Lists.<Collection<DataTreeCandidate>>newArrayList();
+ private final List<DataTreeCandidate> changeList = Lists.newArrayList();
private volatile CountDownLatch changeLatch;
private int expChangeEventCount;
@Override
public void onDataTreeChanged(@Nonnull final Collection<DataTreeCandidate> changes) {
- synchronized (changeList) {
- changeList.add(changes);
+ if (changeLatch.getCount() > 0) {
+ synchronized (changeList) {
+ changeList.addAll(changes);
+ }
+ changeLatch.countDown();
}
- changeLatch.countDown();
}
public void waitForChangeEvents() {
public void verifyNotifiedData(YangInstanceIdentifier... paths) {
Set<YangInstanceIdentifier> pathSet = new HashSet<>(Arrays.asList(paths));
synchronized (changeList) {
- for (Collection<DataTreeCandidate> list : changeList) {
- for (DataTreeCandidate c : list) {
- pathSet.remove(c.getRootPath());
- }
+ for (DataTreeCandidate c : changeList) {
+ pathSet.remove(c.getRootPath());
}
}
public void verifyNoNotifiedData(YangInstanceIdentifier... paths) {
Set<YangInstanceIdentifier> pathSet = new HashSet<>(Arrays.asList(paths));
synchronized (changeList) {
- for (Collection<DataTreeCandidate> list : changeList) {
- for (DataTreeCandidate c : list) {
- assertFalse("Unexpected " + c.getRootPath() + " present in DataTreeCandidate",
- pathSet.contains(c.getRootPath()));
- }
+ for (DataTreeCandidate c : changeList) {
+ assertFalse("Unexpected " + c.getRootPath() + " present in DataTreeCandidate",
+ pathSet.contains(c.getRootPath()));
}
}
}