From 552a5e7e85278c20319693d269c177d9c5cc756e Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 19 Sep 2017 10:42:39 +0300 Subject: [PATCH] Transition ListenerAdapter to ClusteredDOMDataTreeListener Solves this: https://bugs.opendaylight.org/show_bug.cgi?id=9147 This is in general an issue with ListenerAdapter which does not currently work in a clustered deployment. ListenerAdapterTest needed to be adjusted for two reasons: 1. There was a bug in ListenerAdapter where if leafNodesOnly was set the leafNodesOnly logic was not applied in delete notifications. The new ListenerAdapter code fixes that so ListenerAdapterTest needed to be adjusted. 2. In DomDataTreeEtc, merge operations cause the key node to count as "WRITE"-en for notifications even if it was not changed. ListenerAdapterTest was adjusted accordingly. Bug for this here: https://bugs.opendaylight.org/show_bug.cgi?id=9179 Change-Id: I3c40e02551d8f04354489e5ffb8c66f111bb3b96 Signed-off-by: Josh --- .../sal/restconf/impl/BrokerFacade.java | 15 +- .../streams/listeners/ListenerAdapter.java | 136 ++++++++++-------- .../restconf/impl/test/BrokerFacadeTest.java | 22 ++- ...stconfImplNotificationSubscribingTest.java | 8 +- .../listeners/ListenerAdapterTest.java | 25 ++-- .../notif-leaves-del.json | 10 +- .../notif-leaves-update.json | 32 +++-- .../listener-adapter-test/notif-update.json | 32 +++-- 8 files changed, 169 insertions(+), 111 deletions(-) diff --git a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java index d2fd193079..85263d056b 100644 --- a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java +++ b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/restconf/impl/BrokerFacade.java @@ -29,10 +29,11 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener; @@ -528,9 +529,15 @@ public class BrokerFacade { } final YangInstanceIdentifier path = listener.getPath(); - final ListenerRegistration registration = this.domDataBroker.registerDataChangeListener( - datastore, path, listener, scope); - + DOMDataTreeChangeService changeService = (DOMDataTreeChangeService) + this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + if (changeService == null) { + throw new UnsupportedOperationException("DOMDataBroker does not support the DOMDataTreeChangeService" + + this.domDataBroker); + } + DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(datastore, path); + ListenerRegistration registration = + changeService.registerDataTreeChangeListener(root, listener); listener.setRegistration(registration); } diff --git a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java index e6e27ccb70..d88f4e5b61 100644 --- a/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java +++ b/restconf/restconf-nb-bierman02/src/main/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapter.java @@ -7,16 +7,16 @@ */ package org.opendaylight.netconf.sal.streams.listeners; +import com.google.common.base.Optional; import com.google.common.base.Preconditions; import java.io.IOException; +import java.util.Collection; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; +import javax.annotation.Nonnull; import javax.xml.stream.XMLStreamException; import javax.xml.transform.dom.DOMResult; import org.json.XML; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; +import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener; import org.opendaylight.netconf.sal.restconf.impl.ControllerContext; import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType; import org.opendaylight.yangtools.yang.common.QName; @@ -28,6 +28,8 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode; +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.util.DataSchemaContextTree; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -42,7 +44,7 @@ import org.w3c.dom.Node; * {@link ListenerAdapter} is responsible to track events, which occurred by * changing data in data source. */ -public class ListenerAdapter extends AbstractCommonSubscriber implements DOMDataChangeListener { +public class ListenerAdapter extends AbstractCommonSubscriber implements ClusteredDOMDataTreeChangeListener { private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class); @@ -50,7 +52,7 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData private final String streamName; private final NotificationOutputType outputType; - private AsyncDataChangeEvent> change; + private Collection dataTreeCandidates; /** * Creates new {@link ListenerAdapter} listener specified by path and stream @@ -74,8 +76,8 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData } @Override - public void onDataChanged(final AsyncDataChangeEvent> change) { - this.change = change; + public void onDataTreeChanged(@Nonnull Collection dataTreeCandidates) { + this.dataTreeCandidates = dataTreeCandidates; final String xml = prepareXml(); if (checkQueryParams(xml, this)) { prepareAndPostData(xml); @@ -139,8 +141,8 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData final Element dataChangedNotificationEventElement = doc.createElementNS( "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification"); - addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, this.change, - schemaContext, dataContextTree); + addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, + this.dataTreeCandidates, schemaContext, dataContextTree); notificationElement.appendChild(dataChangedNotificationEventElement); return transformDoc(doc); } @@ -152,64 +154,84 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData * {@link Document} * @param dataChangedNotificationEventElement * {@link Element} - * @param change - * {@link AsyncDataChangeEvent} + * @param dataTreeCandidates + * {@link DataTreeCandidate} */ private void addValuesToDataChangedNotificationEventElement(final Document doc, final Element dataChangedNotificationEventElement, - final AsyncDataChangeEvent> change, + final Collection dataTreeCandidates, final SchemaContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) { - addCreatedChangedValuesFromDataToElement(doc, change.getCreatedData().entrySet(), - dataChangedNotificationEventElement, Operation.CREATED, schemaContext, dataSchemaContextTree); - - addCreatedChangedValuesFromDataToElement(doc, change.getUpdatedData().entrySet(), - dataChangedNotificationEventElement, Operation.UPDATED, schemaContext, dataSchemaContextTree); - - addValuesFromDataToElement(doc, change.getRemovedPaths(), dataChangedNotificationEventElement, - Operation.DELETED); - } - - /** - * Adds values from data to element. - * - * @param doc - * {@link Document} - * @param data - * Set of {@link YangInstanceIdentifier}. - * @param element - * {@link Element} - * @param operation - * {@link Operation} - */ - private void addValuesFromDataToElement(final Document doc, final Set data, - final Element element, final Operation operation) { - if ((data == null) || data.isEmpty()) { - return; - } - for (final YangInstanceIdentifier path : data) { - if (!ControllerContext.getInstance().isNodeMixin(path)) { - final Node node = createDataChangeEventElement(doc, path, operation); - element.appendChild(node); + for (DataTreeCandidate dataTreeCandidate : dataTreeCandidates) { + DataTreeCandidateNode candidateNode = dataTreeCandidate.getRootNode(); + if (candidateNode == null) { + continue; } + YangInstanceIdentifier yiid = dataTreeCandidate.getRootPath(); + addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode, + yiid.getParent(), schemaContext, dataSchemaContextTree); } } - private void addCreatedChangedValuesFromDataToElement(final Document doc, - final Set>> data, final Element element, - final Operation operation, final SchemaContext schemaContext, - final DataSchemaContextTree dataSchemaContextTree) { - if ((data == null) || data.isEmpty()) { + private void addNodeToDataChangeNotificationEventElement(final Document doc, + final Element dataChangedNotificationEventElement, DataTreeCandidateNode candidateNode, + YangInstanceIdentifier parentYiid, SchemaContext schemaContext, + DataSchemaContextTree dataSchemaContextTree) { + + Optional> optionalNormalizedNode = Optional.absent(); + switch (candidateNode.getModificationType()) { + case APPEARED: + case SUBTREE_MODIFIED: + case WRITE: + optionalNormalizedNode = candidateNode.getDataAfter(); + break; + case DELETE: + case DISAPPEARED: + optionalNormalizedNode = candidateNode.getDataBefore(); + break; + case UNMODIFIED: + default: + break; + } + + if (!optionalNormalizedNode.isPresent()) { + LOG.error("No node present in notification for {}", candidateNode); return; } - for (final Entry> entry : data) { - if (!ControllerContext.getInstance().isNodeMixin(entry.getKey()) - && (!getLeafNodesOnly() || entry.getValue() instanceof LeafNode)) { - final Node node = createCreatedChangedDataChangeEventElement(doc, entry, operation, schemaContext, - dataSchemaContextTree); - element.appendChild(node); + + NormalizedNode normalizedNode = optionalNormalizedNode.get(); + YangInstanceIdentifier yiid = YangInstanceIdentifier.builder(parentYiid) + .append(normalizedNode.getIdentifier()).build(); + + boolean isNodeMixin = ControllerContext.getInstance().isNodeMixin(yiid); + boolean isSkippedNonLeaf = getLeafNodesOnly() && !(normalizedNode instanceof LeafNode); + if (!isNodeMixin && !isSkippedNonLeaf) { + Node node = null; + switch (candidateNode.getModificationType()) { + case APPEARED: + case SUBTREE_MODIFIED: + case WRITE: + Operation op = candidateNode.getDataBefore().isPresent() ? Operation.UPDATED : Operation.CREATED; + node = createCreatedChangedDataChangeEventElement(doc, yiid, normalizedNode, op, + schemaContext, dataSchemaContextTree); + break; + case DELETE: + case DISAPPEARED: + node = createDataChangeEventElement(doc, yiid, Operation.DELETED); + break; + case UNMODIFIED: + default: + break; + } + if (node != null) { + dataChangedNotificationEventElement.appendChild(node); } } + + for (DataTreeCandidateNode childNode : candidateNode.getChildNodes()) { + addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, childNode, + yiid, schemaContext, dataSchemaContextTree); + } } /** @@ -238,11 +260,10 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData } private Node createCreatedChangedDataChangeEventElement(final Document doc, - final Entry> entry, final Operation operation, + YangInstanceIdentifier path, NormalizedNode normalized, final Operation operation, final SchemaContext schemaContext, final DataSchemaContextTree dataSchemaContextTree) { final Element dataChangeEventElement = doc.createElement("data-change-event"); final Element pathElement = doc.createElement("path"); - final YangInstanceIdentifier path = entry.getKey(); addPathAsValueToElement(path, pathElement); dataChangeEventElement.appendChild(pathElement); @@ -252,7 +273,6 @@ public class ListenerAdapter extends AbstractCommonSubscriber implements DOMData try { SchemaPath nodePath; - final NormalizedNode normalized = entry.getValue(); if ((normalized instanceof MapEntryNode) || (normalized instanceof UnkeyedListEntryNode)) { nodePath = dataSchemaContextTree.getChild(path).getDataSchemaNode().getPath(); } else { diff --git a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java index 50f2195302..70e1c340a6 100644 --- a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java +++ b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java @@ -28,20 +28,24 @@ import com.google.common.base.Optional; import com.google.common.collect.Lists; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.Futures; + +import java.util.HashMap; import java.util.concurrent.Future; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService; @@ -113,6 +117,9 @@ public class BrokerFacadeTest { when(this.domDataBroker.newReadOnlyTransaction()).thenReturn(this.readTransaction); when(this.domDataBroker.newWriteOnlyTransaction()).thenReturn(this.writeTransaction); when(this.domDataBroker.newReadWriteTransaction()).thenReturn(this.rwTransaction); + HashMap extensions = new HashMap(); + extensions.put(DOMDataTreeChangeService.class, Mockito.mock(DOMDataTreeChangeService.class)); + when(this.domDataBroker.getSupportedExtensions()).thenReturn(extensions); ControllerContext.getInstance() .setSchemas(TestUtils.loadSchemaContext("/full-versions/test-module", "/modules")); @@ -327,22 +334,23 @@ public class BrokerFacadeTest { NotificationOutputType.XML); @SuppressWarnings("unchecked") - final ListenerRegistration mockRegistration = mock(ListenerRegistration.class); + final ListenerRegistration mockRegistration = mock(ListenerRegistration.class); - when(this.domDataBroker.registerDataChangeListener(any(LogicalDatastoreType.class), eq(this.instanceID), - eq(listener), eq(DataChangeScope.BASE))).thenReturn(mockRegistration); + DOMDataTreeChangeService changeService = (DOMDataTreeChangeService) + this.domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + DOMDataTreeIdentifier loc = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, this.instanceID); + when(changeService.registerDataTreeChangeListener(eq(loc), eq(listener))).thenReturn(mockRegistration); this.brokerFacade.registerToListenDataChanges( LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); - verify(this.domDataBroker).registerDataChangeListener( - LogicalDatastoreType.CONFIGURATION, this.instanceID, listener, DataChangeScope.BASE); + verify(changeService).registerDataTreeChangeListener(loc, listener); assertEquals("isListening", true, listener.isListening()); this.brokerFacade.registerToListenDataChanges( LogicalDatastoreType.CONFIGURATION, DataChangeScope.BASE, listener); - verifyNoMoreInteractions(this.domDataBroker); + verifyNoMoreInteractions(changeService); } /** diff --git a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java index e34f9dbda1..bbac0c5cf6 100644 --- a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java +++ b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java @@ -23,7 +23,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils; import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade; @@ -37,7 +36,7 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; public class RestconfImplNotificationSubscribingTest { @@ -209,11 +208,10 @@ public class RestconfImplNotificationSubscribingTest { subscribe(list); - final AsyncDataChangeEvent> change = - Mockito.mock(AsyncDataChangeEvent.class); + ArrayList candidates = new ArrayList(0); Instant startOrig = listener.getStart(); Assert.assertNotNull(startOrig); - listener.onDataChanged(change); + listener.onDataTreeChanged(candidates); startOrig = listener.getStart(); Assert.assertNull(startOrig); diff --git a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java index 4249f53ecb..41bc13146f 100644 --- a/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java +++ b/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java @@ -24,9 +24,10 @@ import org.junit.Test; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.binding.test.AbstractConcurrentDataBrokerTest; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService; +import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.netconf.sal.restconf.impl.ControllerContext; import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchCont; import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1; @@ -38,8 +39,11 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; import org.skyscreamer.jsonassert.JSONAssert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { + private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapterTest.class); private static final String JSON_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.json"; private static final String JSON_NOTIF_LEAVES_UPDATE = "/listener-adapter-test/notif-leaves-update.json"; @@ -89,6 +93,7 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { } Thread.currentThread().sleep(200); } + LOG.debug("Comparing {} {}", json, lastNotification); JSONAssert.assertEquals(json, withFakeDate(lastNotification), false); this.lastNotification = null; } @@ -112,11 +117,12 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { @Test public void testJsonNotifsLeaves() throws Exception { - ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputTypeGrouping.NotificationOutputType.JSON, true); - domDataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID, adapter, - AsyncDataBroker.DataChangeScope.SUBTREE); + DOMDataTreeChangeService changeService = (DOMDataTreeChangeService) + domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID); + changeService.registerDataTreeChangeListener(root, adapter); WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea"); @@ -127,7 +133,7 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE)); writeTransaction = dataBroker.newWriteOnlyTransaction(); - builder.setMyLeaf12("Bertha"); + builder = new MyList1Builder().setKey(new MyList1Key("Althea")).setMyLeaf12("Bertha"); writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build(), true); writeTransaction.submit(); adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE)); @@ -140,11 +146,12 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { @Test public void testJsonNotifs() throws Exception { - ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputTypeGrouping.NotificationOutputType.JSON, false); - domDataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID, adapter, - AsyncDataBroker.DataChangeScope.SUBTREE); + DOMDataTreeChangeService changeService = (DOMDataTreeChangeService) + domDataBroker.getSupportedExtensions().get(DOMDataTreeChangeService.class); + DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID); + changeService.registerDataTreeChangeListener(root, adapter); WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea"); @@ -155,7 +162,7 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { adapter.assertGot(getNotifJson(JSON_NOTIF_CREATE)); writeTransaction = dataBroker.newWriteOnlyTransaction(); - builder.setMyLeaf12("Bertha"); + builder = new MyList1Builder().setKey(new MyList1Key("Althea")).setMyLeaf12("Bertha"); writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build(), true); writeTransaction.submit(); adapter.assertGot(getNotifJson(JSON_NOTIF_UPDATE)); diff --git a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json index bffe4c3515..5d9e9f1fb2 100644 --- a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json +++ b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-del.json @@ -2,26 +2,22 @@ "notification": { "data-changed-notification": { "data-change-event": [ - { - "operation": "deleted", - "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" - }, { "operation": "deleted", "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf11" }, { "operation": "deleted", - "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']" + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name" }, { "operation": "deleted", - "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name" + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" } ], "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote" }, - "eventTime": "2017-09-17T14:03:35.261+03:00", + "eventTime": "2017-09-18T15:30:16.099+03:00", "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0" } } diff --git a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json index 0adf702b59..ffef66035f 100644 --- a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json +++ b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-leaves-update.json @@ -1,19 +1,31 @@ { "notification": { "data-changed-notification": { - "data-change-event": { - "data": { - "my-leaf12": { - "content": "Bertha", - "xmlns": "instance:identifier:patch:module" - } + "data-change-event": [ + { + "data": { + "my-leaf12": { + "content": "Bertha", + "xmlns": "instance:identifier:patch:module" + } + }, + "operation": "created", + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" }, - "operation": "created", - "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" - }, + { + "data": { + "name": { + "content": "Althea", + "xmlns": "instance:identifier:patch:module" + } + }, + "operation": "updated", + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name" + } + ], "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote" }, - "eventTime": "2017-09-17T13:56:47.032+03:00", + "eventTime": "2017-09-18T14:20:54.82+03:00", "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0" } } diff --git a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json index 065d6205a2..b2957ea99f 100644 --- a/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json +++ b/restconf/restconf-nb-bierman02/src/test/resources/listener-adapter-test/notif-update.json @@ -2,16 +2,6 @@ "notification": { "data-changed-notification": { "data-change-event": [ - { - "data": { - "my-leaf12": { - "content": "Bertha", - "xmlns": "instance:identifier:patch:module" - } - }, - "operation": "created", - "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" - }, { "data": { "patch-cont": { @@ -37,11 +27,31 @@ }, "operation": "updated", "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']" + }, + { + "data": { + "my-leaf12": { + "content": "Bertha", + "xmlns": "instance:identifier:patch:module" + } + }, + "operation": "created", + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:my-leaf12" + }, + { + "data": { + "name": { + "content": "Althea", + "xmlns": "instance:identifier:patch:module" + } + }, + "operation": "updated", + "path": "/instance-identifier-patch-module:patch-cont/instance-identifier-patch-module:my-list1[instance-identifier-patch-module:name='Althea']/instance-identifier-patch-module:name" } ], "xmlns": "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote" }, - "eventTime": "2017-09-17T14:15:05.839+03:00", + "eventTime": "2017-09-18T15:52:25.213+03:00", "xmlns": "urn:ietf:params:xml:ns:netconf:notification:1.0" } } -- 2.36.6