A new filter named "odl-skip-notification-data", similar to "odl-leaf-nodes-only", is added in the subscription API.
Using this filter, Client can get notification without data.
JIRA: NETCONF-689
Change-Id: I0cec77f69cb141fabc9f839c9a91626d3c667655
Signed-off-by: Nikhil Soni <nsoni@luminanetworks.com>
String filter = null;
boolean leafNodesOnlyUsed = false;
boolean leafNodesOnly = false;
+ boolean skipNotificationDataUsed = false;
+ boolean skipNotificationData = false;
for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
switch (entry.getKey()) {
throw new RestconfDocumentedException("Odl-leaf-nodes-only parameter can be used only once.");
}
break;
+ case "odl-skip-notification-data":
+ if (!skipNotificationDataUsed) {
+ skipNotificationDataUsed = true;
+ skipNotificationData = Boolean.parseBoolean(entry.getValue().iterator().next());
+ } else {
+ throw new RestconfDocumentedException(
+ "Odl-skip-notification-data parameter can be used only once.");
+ }
+ break;
default:
throw new RestconfDocumentedException("Bad parameter used with notifications: " + entry.getKey());
}
}
URI response = null;
if (identifier.contains(DATA_SUBSCR)) {
- response = dataSubs(identifier, uriInfo, start, stop, filter, leafNodesOnly);
+ response = dataSubs(identifier, uriInfo, start, stop, filter, leafNodesOnly, skipNotificationData);
} else if (identifier.contains(NOTIFICATION_STREAM)) {
response = notifStream(identifier, uriInfo, start, stop, filter);
}
for (final NotificationListenerAdapter listener : listeners) {
this.broker.registerToListenNotification(listener);
- listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), false);
+ listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), false, false);
}
final UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder();
* @return {@link URI} of location
*/
private URI dataSubs(final String identifier, final UriInfo uriInfo, final Instant start, final Instant stop,
- final String filter, final boolean leafNodesOnly) {
+ final String filter, final boolean leafNodesOnly, final boolean skipNotificationData) {
final String streamName = Notificator.createStreamNameFromUri(identifier);
if (Strings.isNullOrEmpty(streamName)) {
throw new RestconfDocumentedException("Stream name is empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
throw new RestconfDocumentedException("Stream was not found.", ErrorType.PROTOCOL,
ErrorTag.UNKNOWN_ELEMENT);
}
- listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), leafNodesOnly);
+ listener.setQueryParams(start, Optional.ofNullable(stop), Optional.ofNullable(filter), leafNodesOnly,
+ skipNotificationData);
final Map<String, String> paramToValues = resolveValuesFromUri(identifier);
final LogicalDatastoreType datastore =
private Instant stop = null;
private String filter = null;
private boolean leafNodesOnly = false;
+ private boolean skipNotificationData = false;
@VisibleForTesting
public final Instant getStart() {
* indicate which subset of all possible events are of interest
* @param leafNodesOnly
* if true, notifications will contain changes to leaf nodes only
+ * @param skipNotificationData
+ * if true, notification will not contain changed data
*/
@SuppressWarnings("checkstyle:hiddenField")
public void setQueryParams(final Instant start, final Optional<Instant> stop, final Optional<String> filter,
- final boolean leafNodesOnly) {
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
this.start = requireNonNull(start);
this.stop = stop.orElse(null);
this.filter = filter.orElse(null);
this.leafNodesOnly = leafNodesOnly;
+ this.skipNotificationData = skipNotificationData;
}
/**
return leafNodesOnly;
}
+ /**
+ * Check whether this query should notify changes without data.
+ *
+ * @return true if this query should notify about changes with data
+ */
+ public boolean isSkipNotificationData() {
+ return skipNotificationData;
+ }
+
@SuppressWarnings("checkstyle:IllegalCatch")
<T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
if (this.stop != null) {
public class ListenerAdapter extends AbstractCommonSubscriber implements ClusteredDOMDataTreeChangeListener {
private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class);
+ private static final String DATA_CHANGE_EVENT = "data-change-event";
+ private static final String PATH = "path";
+ private static final String OPERATION = "operation";
private final ControllerContext controllerContext;
private final YangInstanceIdentifier path;
continue;
}
YangInstanceIdentifier yiid = dataTreeCandidate.getRootPath();
- addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode,
- yiid.getParent(), schemaContext, dataSchemaContextTree);
+
+ boolean isSkipNotificationData = this.isSkipNotificationData();
+ if (isSkipNotificationData) {
+ createCreatedChangedDataChangeEventElementWithoutData(doc,
+ dataChangedNotificationEventElement, dataTreeCandidate.getRootNode());
+ } else {
+ addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode,
+ yiid.getParent(), schemaContext, dataSchemaContextTree);
+ }
}
}
*/
private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier dataPath,
final Operation operation) {
- final Element dataChangeEventElement = doc.createElement("data-change-event");
- final Element pathElement = doc.createElement("path");
+ final Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
addPathAsValueToElement(dataPath, pathElement);
dataChangeEventElement.appendChild(pathElement);
- final Element operationElement = doc.createElement("operation");
+ final Element operationElement = doc.createElement(OPERATION);
operationElement.setTextContent(operation.value);
dataChangeEventElement.appendChild(operationElement);
return dataChangeEventElement;
}
+ /**
+ * Creates data change notification element without data element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataChangedNotificationEventElement
+ * {@link Element}
+ * @param candidateNode
+ * {@link DataTreeCandidateNode}
+ */
+ private void createCreatedChangedDataChangeEventElementWithoutData(final Document doc,
+ final Element dataChangedNotificationEventElement, final DataTreeCandidateNode candidateNode) {
+ final Operation operation;
+ switch (candidateNode.getModificationType()) {
+ case APPEARED:
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ operation = candidateNode.getDataBefore().isPresent() ? Operation.UPDATED : Operation.CREATED;
+ break;
+ case DELETE:
+ case DISAPPEARED:
+ operation = Operation.DELETED;
+ break;
+ case UNMODIFIED:
+ default:
+ return;
+ }
+ Node dataChangeEventElement = createDataChangeEventElement(doc, getPath(), operation);
+ dataChangedNotificationEventElement.appendChild(dataChangeEventElement);
+
+ }
+
private Node createCreatedChangedDataChangeEventElement(final Document doc,
final YangInstanceIdentifier eventPath, final 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 Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
addPathAsValueToElement(eventPath, pathElement);
dataChangeEventElement.appendChild(pathElement);
- final Element operationElement = doc.createElement("operation");
+ final Element operationElement = doc.createElement(OPERATION);
operationElement.setTextContent(operation.value);
dataChangeEventElement.appendChild(operationElement);
Mockito.when(path.getLastPathArgument()).thenReturn(pathValue);
final ListenerAdapter listener = Notificator.createListener(path, "streamName", NotificationOutputType.JSON,
null);
- listener.setQueryParams(Instant.now(), Optional.empty(), Optional.ofNullable(filter), false);
+ listener.setQueryParams(Instant.now(), Optional.empty(), Optional.ofNullable(filter), false, false);
// FIXME: do not use reflection here
final Class<?> superclass = listener.getClass().getSuperclass().getSuperclass();
private static final String JSON_NOTIF_CREATE = "/listener-adapter-test/notif-create.json";
private static final String JSON_NOTIF_UPDATE = "/listener-adapter-test/notif-update.json";
private static final String JSON_NOTIF_DEL = "/listener-adapter-test/notif-del.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_CREATE =
+ "/listener-adapter-test/notif-without-data-create.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_UPDATE =
+ "/listener-adapter-test/notif-without-data-update.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_DELETE =
+ "/listener-adapter-test/notif-without-data-del.json";
+
private static final YangInstanceIdentifier PATCH_CONT_YIID =
YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(PatchCont.QNAME));
private String lastNotification = null;
ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
- final NotificationOutputTypeGrouping.NotificationOutputType outputType,
- final boolean leafNodesOnly) {
+ final NotificationOutputTypeGrouping.NotificationOutputType outputType,
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
super(path, streamName, outputType, controllerContext);
- setQueryParams(EPOCH, Optional.empty(), Optional.empty(), leafNodesOnly);
+ setQueryParams(EPOCH, Optional.empty(), Optional.empty(), leafNodesOnly, skipNotificationData);
}
@Override
@Test
public void testJsonNotifsLeaves() throws Exception {
ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
- NotificationOutputTypeGrouping.NotificationOutputType.JSON, true);
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, true, false);
DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
.getInstance(DOMDataTreeChangeService.class);
DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
@Test
public void testJsonNotifs() throws Exception {
ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
- NotificationOutputTypeGrouping.NotificationOutputType.JSON, false);
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, false);
DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
.getInstance(DOMDataTreeChangeService.class);
DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
writeTransaction.commit();
adapter.assertGot(getNotifJson(JSON_NOTIF_DEL));
}
+
+ @Test
+ public void testJsonNotifsWithoutData() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, true);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(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");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_DELETE));
+ }
}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"created"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"deleted"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"updated"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
private final Instant start;
private final Instant stop;
private final String filter;
+ private final boolean skipNotificationData;
- private NotificationQueryParams(final Instant start, final Instant stop, final String filter) {
+ private NotificationQueryParams(final Instant start, final Instant stop, final String filter,
+ final boolean skipNotificationData) {
this.start = start == null ? Instant.now() : start;
this.stop = stop;
this.filter = filter;
+ this.skipNotificationData = skipNotificationData;
}
static NotificationQueryParams fromUriInfo(final UriInfo uriInfo) {
boolean stopTimeUsed = false;
String filter = null;
boolean filterUsed = false;
+ boolean skipNotificationDataUsed = false;
+ boolean skipNotificationData = false;
for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
switch (entry.getKey()) {
filter = entry.getValue().iterator().next();
}
break;
+ case "odl-skip-notification-data":
+ if (!skipNotificationDataUsed) {
+ skipNotificationDataUsed = true;
+ skipNotificationData = Boolean.parseBoolean(entry.getValue().iterator().next());
+ } else {
+ throw new RestconfDocumentedException(
+ "Odl-skip-notification-data parameter can be used only once.");
+ }
+ break;
default:
throw new RestconfDocumentedException(
"Bad parameter used with notifications: " + entry.getKey());
throw new RestconfDocumentedException("Stop-time parameter has to be used with start-time parameter.");
}
- return new NotificationQueryParams(start, stop, filter);
+ return new NotificationQueryParams(start, stop, filter, skipNotificationData);
}
public Optional<String> getFilter() {
return Optional.ofNullable(filter);
}
+
+ /**
+ * Check whether this query should notify changes without data.
+ *
+ * @return true if this query should notify about changes with data
+ */
+ public boolean isSkipNotificationData() {
+ return skipNotificationData;
+ }
}
-}
\ No newline at end of file
+}
notificationQueryParams.getStart(),
notificationQueryParams.getStop().orElse(null),
notificationQueryParams.getFilter().orElse(null),
- false);
+ false, notificationQueryParams.isSkipNotificationData());
notificationListenerAdapter.get().setCloseVars(
handlersHolder.getTransactionChainHandler(), handlersHolder.getSchemaHandler());
final NormalizedNode<?, ?> mapToStreams =
notificationQueryParams.getStart(),
notificationQueryParams.getStop().orElse(null),
notificationQueryParams.getFilter().orElse(null),
- false);
+ false, notificationQueryParams.isSkipNotificationData());
listener.get().setCloseVars(handlersHolder.getTransactionChainHandler(), handlersHolder.getSchemaHandler());
registration(datastoreType, listener.get(), handlersHolder.getDomDataBrokerHandler().get());
private Instant stop = null;
private String filter = null;
private boolean leafNodesOnly = false;
+ private boolean skipNotificationData = false;
@VisibleForTesting
public final Instant getStart() {
*/
@SuppressWarnings("checkstyle:hiddenField")
public void setQueryParams(final Instant start, final Instant stop, final String filter,
- final boolean leafNodesOnly) {
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
this.start = requireNonNull(start);
this.stop = stop;
this.filter = filter;
this.leafNodesOnly = leafNodesOnly;
+ this.skipNotificationData = skipNotificationData;
}
/**
return leafNodesOnly;
}
+ /**
+ * Check whether this query should notify changes without data.
+ *
+ * @return true if this query should notify about changes with data
+ */
+ public boolean isSkipNotificationData() {
+ return skipNotificationData;
+ }
+
@SuppressWarnings("checkstyle:IllegalCatch")
<T extends BaseListenerInterface> boolean checkStartStop(final Instant now, final T listener) {
if (this.stop != null) {
// FIXME: BUG-7956: xPath.setNamespaceContext(nsContext);
return (boolean) xPath.compile(this.filter).evaluate(docOfXml, XPathConstants.BOOLEAN);
}
-}
\ No newline at end of file
+}
public class ListenerAdapter extends AbstractCommonSubscriber implements ClusteredDOMDataTreeChangeListener {
private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class);
+ private static final String DATA_CHANGE_EVENT = "data-change-event";
+ private static final String PATH = "path";
+ private static final String OPERATION = "operation";
private final YangInstanceIdentifier path;
private final String streamName;
continue;
}
YangInstanceIdentifier yiid = dataTreeCandidate.getRootPath();
- addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode,
- yiid.getParent(), schemaContext, dataSchemaContextTree);
+ boolean isSkipNotificationData = this.isSkipNotificationData();
+ if (isSkipNotificationData) {
+ createCreatedChangedDataChangeEventElementWithoutData(doc, dataChangedNotificationEventElement,
+ dataTreeCandidate.getRootNode(), schemaContext);
+ } else {
+ addNodeToDataChangeNotificationEventElement(doc, dataChangedNotificationEventElement, candidateNode,
+ yiid.getParent(), schemaContext, dataSchemaContextTree);
+ }
}
}
break;
case DELETE:
case DISAPPEARED:
- node = createDataChangeEventElement(doc, yiid, schemaContext);
+ node = createDataChangeEventElement(doc, yiid, schemaContext, Operation.DELETED);
break;
case UNMODIFIED:
default:
*
* @param doc {@link Document}
* @param schemaContext Schema context.
+ * @param operation Operation value
* @return {@link Node} represented by changed event element.
*/
private static Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier eventPath,
- final SchemaContext schemaContext) {
- final Element dataChangeEventElement = doc.createElement("data-change-event");
- final Element pathElement = doc.createElement("path");
+ final SchemaContext schemaContext, Operation operation) {
+ final Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
addPathAsValueToElement(eventPath, pathElement, schemaContext);
dataChangeEventElement.appendChild(pathElement);
- final Element operationElement = doc.createElement("operation");
- operationElement.setTextContent(Operation.DELETED.value);
+ final Element operationElement = doc.createElement(OPERATION);
+ operationElement.setTextContent(operation.value);
dataChangeEventElement.appendChild(operationElement);
return dataChangeEventElement;
}
+ /**
+ * Creates data change notification element without data element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataChangedNotificationEventElement
+ * {@link Element}
+ * @param candidateNode
+ * {@link DataTreeCandidateNode}
+ */
+ private void createCreatedChangedDataChangeEventElementWithoutData(final Document doc,
+ final Element dataChangedNotificationEventElement, final DataTreeCandidateNode candidateNode,
+ final SchemaContext schemaContext) {
+ final Operation operation;
+ switch (candidateNode.getModificationType()) {
+ case APPEARED:
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ operation = candidateNode.getDataBefore().isPresent() ? Operation.UPDATED : Operation.CREATED;
+ break;
+ case DELETE:
+ case DISAPPEARED:
+ operation = Operation.DELETED;
+ break;
+ case UNMODIFIED:
+ default:
+ return;
+ }
+ Node dataChangeEventElement = createDataChangeEventElement(doc, getPath(), schemaContext, operation);
+ dataChangedNotificationEventElement.appendChild(dataChangeEventElement);
+ }
+
private Node createCreatedChangedDataChangeEventElement(final Document doc, final YangInstanceIdentifier eventPath,
final 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 Element dataChangeEventElement = doc.createElement(DATA_CHANGE_EVENT);
+ final Element pathElement = doc.createElement(PATH);
addPathAsValueToElement(eventPath, pathElement, schemaContext);
dataChangeEventElement.appendChild(pathElement);
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
- .add("path", path)
+ .add(PATH, path)
.add("stream-name", streamName)
.add("output-type", outputType)
.toString();
}
-}
\ No newline at end of file
+}
private static final String JSON_NOTIF_CREATE = "/listener-adapter-test/notif-create.json";
private static final String JSON_NOTIF_UPDATE = "/listener-adapter-test/notif-update.json";
private static final String JSON_NOTIF_DEL = "/listener-adapter-test/notif-del.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_CREATE =
+ "/listener-adapter-test/notif-without-data-create.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_UPDATE =
+ "/listener-adapter-test/notif-without-data-update.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_DELETE =
+ "/listener-adapter-test/notif-without-data-del.json";
private static final YangInstanceIdentifier PATCH_CONT_YIID =
YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(PatchCont.QNAME));
ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
final NotificationOutputTypeGrouping.NotificationOutputType outputType,
- final boolean leafNodesOnly) {
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
super(path, streamName, outputType);
- setQueryParams(EPOCH, null, null, leafNodesOnly);
+ setQueryParams(EPOCH, null, null, leafNodesOnly, skipNotificationData);
}
@Override
@Test
public void testJsonNotifsLeaves() throws Exception {
ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
- NotificationOutputTypeGrouping.NotificationOutputType.JSON, true);
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, true, false);
adapter.setCloseVars(transactionChainHandler, schemaContextHandler);
DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
@Test
public void testJsonNotifs() throws Exception {
ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
- NotificationOutputTypeGrouping.NotificationOutputType.JSON, false);
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, false);
adapter.setCloseVars(transactionChainHandler, schemaContextHandler);
DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
writeTransaction.commit();
adapter.assertGot(getNotifJson(JSON_NOTIF_DEL));
}
+
+ @Test
+ public void testJsonNotifsWithoutData() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, true);
+ adapter.setCloseVars(transactionChainHandler, schemaContextHandler);
+
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(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");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_DELETE));
+ }
}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"created"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"deleted"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}
--- /dev/null
+{
+ "notification":{
+ "xmlns":"urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "data-changed-notification":{
+ "xmlns":"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-change-event":{
+ "path":"/instance-identifier-patch-module:patch-cont",
+ "operation":"updated"
+ }
+ },
+ "eventTime":"2020-05-31T18:45:05.132101+05:30"
+ }
+}