From: Olivier Dugeon Date: Wed, 21 Jun 2023 08:35:21 +0000 (+0200) Subject: Add Child Nodes Only query parameter to SSE events X-Git-Tag: v7.0.0~600 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=35da710e64c6dc63b12c5a998e40e5abcc615c09;p=netconf.git Add Child Nodes Only query parameter to SSE events For SSE or Websocket, events are reported from the root node of the listen Data Tree or from the modified leafs with the 'odl-leaf-nodes-only=true' query parameter. This patch introduce a new 'odl-child-nodes-only' query parameter to get only modified children in a compact form. This new option could be considered as something in the middle between getting the whole Data Tree from the root node and a per leaf node report. JIRA: NETCONF-1076 Change-Id: Ibeda878a38a52f911dd8fbaa0503c4bfb56ea9b7 Signed-off-by: Olivier Dugeon Signed-off-by: Robert Varga --- diff --git a/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/ChildNodesOnlyParam.java b/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/ChildNodesOnlyParam.java new file mode 100644 index 0000000000..9fc8662eae --- /dev/null +++ b/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/ChildNodesOnlyParam.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Orange and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.restconf.api.query; + +import java.net.URI; +import org.eclipse.jdt.annotation.NonNull; + +/** + * OpenDaylight extension parameter. When used as {@code odl-child-nodes-only=true}, it will instruct the listener + * streams to only emit child nodes. + */ +public final class ChildNodesOnlyParam implements RestconfQueryParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final String uriName = "odl-child-nodes-only"; + + private static final @NonNull URI CAPABILITY = + URI.create("urn:opendaylight:params:restconf:capability:child-nodes-only:1.0"); + private static final @NonNull ChildNodesOnlyParam FALSE = new ChildNodesOnlyParam(false); + private static final @NonNull ChildNodesOnlyParam TRUE = new ChildNodesOnlyParam(true); + + private final boolean value; + + private ChildNodesOnlyParam(final boolean value) { + this.value = value; + } + + public static @NonNull ChildNodesOnlyParam of(final boolean value) { + return value ? TRUE : FALSE; + } + + public static @NonNull ChildNodesOnlyParam forUriValue(final String uriValue) { + return switch (uriValue) { + case "false" -> FALSE; + case "true" -> TRUE; + default -> throw new IllegalArgumentException("Value can be 'false' or 'true', not '" + uriValue + "'"); + }; + } + + @Override + public Class javaClass() { + return ChildNodesOnlyParam.class; + } + + @Override + public String paramName() { + return uriName; + } + + @Override + public String paramValue() { + return String.valueOf(value); + } + + public boolean value() { + return value; + } + + public static @NonNull URI capabilityUri() { + return CAPABILITY; + } +} diff --git a/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/RestconfQueryParam.java b/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/RestconfQueryParam.java index 9cd70d6c7a..0fc404b24f 100644 --- a/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/RestconfQueryParam.java +++ b/protocol/restconf-api/src/main/java/org/opendaylight/restconf/api/query/RestconfQueryParam.java @@ -25,7 +25,9 @@ import org.opendaylight.yangtools.concepts.Immutable; public sealed interface RestconfQueryParam> extends Immutable permits ContentParam, DepthParam, FieldsParam, FilterParam, InsertParam, PointParam, WithDefaultsParam, AbstractReplayParam, - ChangedLeafNodesOnlyParam, LeafNodesOnlyParam, PrettyPrintParam, SkipNotificationDataParam { + // ODL extensions + ChangedLeafNodesOnlyParam, LeafNodesOnlyParam, PrettyPrintParam, SkipNotificationDataParam, + ChildNodesOnlyParam { /** * Return the Java representation class. * diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java index ae586892af..56bad1b86d 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java @@ -12,6 +12,7 @@ import com.google.common.base.MoreObjects; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.restconf.api.query.ChangedLeafNodesOnlyParam; +import org.opendaylight.restconf.api.query.ChildNodesOnlyParam; import org.opendaylight.restconf.api.query.FilterParam; import org.opendaylight.restconf.api.query.LeafNodesOnlyParam; import org.opendaylight.restconf.api.query.SkipNotificationDataParam; @@ -29,33 +30,41 @@ public final class NotificationQueryParams implements Immutable { private final StopTimeParam stopTime; private final FilterParam filter; private final ChangedLeafNodesOnlyParam changedLeafNodesOnly; + private final ChildNodesOnlyParam childNodesOnly; private NotificationQueryParams(final StartTimeParam startTime, final StopTimeParam stopTime, final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly, - final SkipNotificationDataParam skipNotificationData, - final ChangedLeafNodesOnlyParam changedLeafNodesOnly) { + final SkipNotificationDataParam skipNotificationData, final ChangedLeafNodesOnlyParam changedLeafNodesOnly, + final ChildNodesOnlyParam childNodesOnly) { this.startTime = startTime; this.stopTime = stopTime; this.filter = filter; this.leafNodesOnly = leafNodesOnly; this.skipNotificationData = skipNotificationData; this.changedLeafNodesOnly = changedLeafNodesOnly; + this.childNodesOnly = childNodesOnly; } public static @NonNull NotificationQueryParams of(final StartTimeParam startTime, final StopTimeParam stopTime, final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly, - final SkipNotificationDataParam skipNotificationData, - final ChangedLeafNodesOnlyParam changedLeafNodesOnly) { + final SkipNotificationDataParam skipNotificationData, final ChangedLeafNodesOnlyParam changedLeafNodesOnly, + final ChildNodesOnlyParam childNodesOnly) { if (stopTime != null && startTime == null) { throw new IllegalArgumentException(StopTimeParam.uriName + " parameter has to be used with " + StartTimeParam.uriName + " parameter"); } - if (changedLeafNodesOnly != null && leafNodesOnly != null) { - throw new IllegalArgumentException(ChangedLeafNodesOnlyParam.uriName + " parameter cannot be used with " - + LeafNodesOnlyParam.uriName + " parameter"); + if (changedLeafNodesOnly != null) { + if (leafNodesOnly != null) { + throw new IllegalArgumentException(ChangedLeafNodesOnlyParam.uriName + " parameter cannot be used with " + + LeafNodesOnlyParam.uriName + " parameter"); + } + if (childNodesOnly != null) { + throw new IllegalArgumentException(ChangedLeafNodesOnlyParam.uriName + " parameter cannot be used with " + + ChildNodesOnlyParam.uriName + " parameter"); + } } return new NotificationQueryParams(startTime, stopTime, filter, leafNodesOnly, skipNotificationData, - changedLeafNodesOnly); + changedLeafNodesOnly, childNodesOnly); } /** @@ -112,6 +121,15 @@ public final class NotificationQueryParams implements Immutable { return changedLeafNodesOnly; } + /** + * Get odl-child-nodes-only query parameter. + * + * @return odl-child-nodes-only + */ + public @Nullable ChildNodesOnlyParam childNodesOnly() { + return childNodesOnly; + } + @Override public String toString() { final var helper = MoreObjects.toStringHelper(this); @@ -133,6 +151,9 @@ public final class NotificationQueryParams implements Immutable { if (changedLeafNodesOnly != null) { helper.add("changedLeafNodesOnly", changedLeafNodesOnly.value()); } + if (childNodesOnly != null) { + helper.add("childNodesOnly", childNodesOnly.value()); + } return helper.toString(); } } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java index 4c6e77603a..7b47555ce9 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java @@ -19,6 +19,7 @@ import javax.ws.rs.core.UriInfo; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.restconf.api.query.ChangedLeafNodesOnlyParam; +import org.opendaylight.restconf.api.query.ChildNodesOnlyParam; import org.opendaylight.restconf.api.query.ContentParam; import org.opendaylight.restconf.api.query.DepthParam; import org.opendaylight.restconf.api.query.FieldsParam; @@ -53,7 +54,8 @@ public final class QueryParams { InsertParam.uriName, PointParam.uriName, // Notifications FilterParam.uriName, StartTimeParam.uriName, StopTimeParam.uriName, - LeafNodesOnlyParam.uriName, SkipNotificationDataParam.uriName, ChangedLeafNodesOnlyParam.uriName); + LeafNodesOnlyParam.uriName, SkipNotificationDataParam.uriName, ChangedLeafNodesOnlyParam.uriName, + ChildNodesOnlyParam.uriName); private QueryParams() { // Utility class @@ -66,6 +68,7 @@ public final class QueryParams { LeafNodesOnlyParam leafNodesOnly = null; SkipNotificationDataParam skipNotificationData = null; ChangedLeafNodesOnlyParam changedLeafNodesOnly = null; + ChildNodesOnlyParam childNodesOnly = null; for (Entry> entry : uriInfo.getQueryParameters().entrySet()) { final String paramName = entry.getKey(); @@ -93,6 +96,9 @@ public final class QueryParams { changedLeafNodesOnly = optionalParam(ChangedLeafNodesOnlyParam::forUriValue, paramName, paramValues); break; + case ChildNodesOnlyParam.uriName: + childNodesOnly = optionalParam(ChildNodesOnlyParam::forUriValue, paramName, paramValues); + break; default: throw unhandledParam("notification", paramName); } @@ -104,7 +110,7 @@ public final class QueryParams { try { return NotificationQueryParams.of(startTime, stopTime, filter, leafNodesOnly, skipNotificationData, - changedLeafNodesOnly); + changedLeafNodesOnly, childNodesOnly); } catch (IllegalArgumentException e) { throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e); } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriter.java index 7fb869506d..bd1fa395bb 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriter.java @@ -27,6 +27,7 @@ import org.opendaylight.mdsal.dom.api.DOMTransactionChain; import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener; import org.opendaylight.restconf.api.query.AbstractReplayParam; import org.opendaylight.restconf.api.query.ChangedLeafNodesOnlyParam; +import org.opendaylight.restconf.api.query.ChildNodesOnlyParam; import org.opendaylight.restconf.api.query.DepthParam; import org.opendaylight.restconf.api.query.FieldsParam; import org.opendaylight.restconf.api.query.FilterParam; @@ -204,6 +205,7 @@ public final class CapabilitiesWriter .withChildValue(LeafNodesOnlyParam.capabilityUri().toString()) .withChildValue(ChangedLeafNodesOnlyParam.capabilityUri().toString()) .withChildValue(SkipNotificationDataParam.capabilityUri().toString()) + .withChildValue(ChildNodesOnlyParam.capabilityUri().toString()) .build(); } } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractCommonSubscriber.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractCommonSubscriber.java index beda17a456..9cbae2d7ca 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractCommonSubscriber.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractCommonSubscriber.java @@ -66,6 +66,7 @@ abstract class AbstractCommonSubscriber extends AbstractNotificationsData imp private boolean leafNodesOnly = false; private boolean skipNotificationData = false; private boolean changedLeafNodesOnly = false; + private boolean childNodesOnly = false; private EventFormatter formatter; AbstractCommonSubscriber(final String streamName, final NotificationOutputType outputType, @@ -150,6 +151,9 @@ abstract class AbstractCommonSubscriber extends AbstractNotificationsData imp final var changedLeafNodes = params.changedLeafNodesOnly(); changedLeafNodesOnly = changedLeafNodes != null && changedLeafNodes.value(); + final var childNodes = params.childNodesOnly(); + childNodesOnly = childNodes != null && childNodes.value(); + final var filter = params.filter(); final String filterValue = filter == null ? null : filter.paramValue(); if (filterValue != null && !filterValue.isEmpty()) { @@ -190,6 +194,15 @@ abstract class AbstractCommonSubscriber extends AbstractNotificationsData imp return skipNotificationData; } + /** + * Check whether this query should only notify about child node changes. + * + * @return true if this query should only notify about child node changes + */ + final boolean getChildNodesOnly() { + return childNodesOnly; + } + final EventFormatter formatter() { return formatter; } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractNotificationListenerAdaptor.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractNotificationListenerAdaptor.java index 7cab6107c5..35371d4f9a 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractNotificationListenerAdaptor.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractNotificationListenerAdaptor.java @@ -51,7 +51,7 @@ abstract class AbstractNotificationListenerAdaptor extends AbstractCommonSubscri final Optional maybeOutput; try { maybeOutput = formatter().eventData(effectiveModel(), notification, eventInstant, getLeafNodesOnly(), - isSkipNotificationData(), getChangedLeafNodesOnly()); + isSkipNotificationData(), getChangedLeafNodesOnly(), getChildNodesOnly()); } catch (Exception e) { LOG.error("Failed to process notification {}", notification, e); return; diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractWebsocketSerializer.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractWebsocketSerializer.java index e886a72299..0185e83284 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractWebsocketSerializer.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractWebsocketSerializer.java @@ -44,17 +44,26 @@ abstract class AbstractWebsocketSerializer { } public final boolean serialize(final DataTreeCandidate candidate, final boolean leafNodesOnly, - final boolean skipData, final boolean changedLeafNodesOnly) throws T { + final boolean skipData, final boolean changedLeafNodesOnly, final boolean childNodesOnly) throws T { if (leafNodesOnly || changedLeafNodesOnly) { - final var path = new ArrayDeque(); - path.addAll(candidate.getRootPath().getPathArguments()); - return serializeLeafNodesOnly(path, candidate.getRootNode(), skipData, changedLeafNodesOnly); + return serializeLeafNodesOnly(mutableRootPath(candidate), candidate.getRootNode(), skipData, + changedLeafNodesOnly); + } + if (childNodesOnly) { + serializeChildNodesOnly(mutableRootPath(candidate), candidate.getRootNode(), skipData); + return true; } serializeData(candidate.getRootPath().getPathArguments(), candidate.getRootNode(), skipData); return true; } + private static Deque mutableRootPath(final DataTreeCandidate candidate) { + final var ret = new ArrayDeque(); + ret.addAll(candidate.getRootPath().getPathArguments()); + return ret; + } + final boolean serializeLeafNodesOnly(final Deque path, final DataTreeCandidateNode candidate, final boolean skipData, final boolean changedLeafNodesOnly) throws T { final var node = switch (candidate.modificationType()) { @@ -111,6 +120,22 @@ abstract class AbstractWebsocketSerializer { return ret; } + private void serializeChildNodesOnly(final Deque path, final DataTreeCandidateNode current, + final boolean skipData) throws T { + switch (current.modificationType()) { + // just a subtree modification, recurse + case SUBTREE_MODIFIED -> { + for (var child : current.childNodes()) { + path.add(child.name()); + serializeChildNodesOnly(path, child, skipData); + path.removeLast(); + } + } + // other modification, serialize it + default -> serializeData(path, current, skipData); + } + } + private void serializeData(final Collection dataPath, final DataTreeCandidateNode candidate, final boolean skipData) throws T { var stack = SchemaInferenceStack.of(context); diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/EventFormatter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/EventFormatter.java index aeeaedf601..89584ef818 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/EventFormatter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/EventFormatter.java @@ -55,7 +55,7 @@ abstract class EventFormatter implements Immutable { private final XPathExpression filter; EventFormatter() { - this.filter = null; + filter = null; } EventFormatter(final String xpathFilter) throws XPathExpressionException { @@ -68,14 +68,13 @@ abstract class EventFormatter implements Immutable { } final Optional eventData(final EffectiveModelContext schemaContext, final T input, final Instant now, - final boolean leafNodesOnly, final boolean skipData, - final boolean changedLeafNodesOnly) - throws Exception { + final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly, + final boolean childNodeOnly) throws Exception { if (!filterMatches(schemaContext, input, now)) { return Optional.empty(); } return Optional.ofNullable( - createText(schemaContext, input, now, leafNodesOnly, skipData, changedLeafNodesOnly)); + createText(schemaContext, input, now, leafNodesOnly, skipData, changedLeafNodesOnly, childNodeOnly)); } /** @@ -97,11 +96,12 @@ abstract class EventFormatter implements Immutable { * @param leafNodesOnly option to include only leaves in the result * @param skipData option to skip data in the result, only paths would be included * @param changedLeafNodesOnly option to include only changed leaves in the result + * @param childNodesOnly option to include only children in the result * @return String representation of the formatted data * @throws Exception if the underlying formatters fail to export the data to the requested format */ abstract String createText(EffectiveModelContext schemaContext, T input, Instant now, boolean leafNodesOnly, - boolean skipData, boolean changedLeafNodesOnly) throws Exception; + boolean skipData, boolean changedLeafNodesOnly, boolean childNodeOnly) throws Exception; private boolean filterMatches(final EffectiveModelContext schemaContext, final T input, final Instant now) throws IOException { diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONDataTreeCandidateFormatter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONDataTreeCandidateFormatter.java index 62f82329ee..226db6a7a4 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONDataTreeCandidateFormatter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONDataTreeCandidateFormatter.java @@ -54,9 +54,8 @@ public final class JSONDataTreeCandidateFormatter extends DataTreeCandidateForma @Override String createText(final EffectiveModelContext schemaContext, final Collection input, - final Instant now, final boolean leafNodesOnly, final boolean skipData, - final boolean changedLeafNodesOnly) - throws IOException { + final Instant now, final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly, + final boolean childNodesOnly) throws IOException { final Writer writer = new StringWriter(); final JsonWriter jsonWriter = new JsonWriter(writer).beginObject(); @@ -67,7 +66,7 @@ public final class JSONDataTreeCandidateFormatter extends DataTreeCandidateForma final var serializer = new JsonDataTreeCandidateSerializer(schemaContext, codecSupplier, jsonWriter); boolean nonEmpty = false; for (var candidate : input) { - nonEmpty |= serializer.serialize(candidate, leafNodesOnly, skipData, changedLeafNodesOnly); + nonEmpty |= serializer.serialize(candidate, leafNodesOnly, skipData, changedLeafNodesOnly, childNodesOnly); } // data-change-event diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONNotificationFormatter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONNotificationFormatter.java index ee0d2fcc83..9f49866218 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONNotificationFormatter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JSONNotificationFormatter.java @@ -51,8 +51,8 @@ final class JSONNotificationFormatter extends NotificationFormatter { @Override String createText(final EffectiveModelContext schemaContext, final DOMNotification input, final Instant now, - final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly) - throws IOException { + final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly, + final boolean childNodesOnly) throws IOException { final Writer writer = new StringWriter(); final JsonWriter jsonWriter = new JsonWriter(writer).beginObject(); jsonWriter.name("ietf-restconf:notification").beginObject(); diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapter.java index 22a422f2bc..38f767d101 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapter.java @@ -76,7 +76,7 @@ public class ListenerAdapter extends AbstractCommonSubscriber maybeData; try { maybeData = formatter().eventData(databindProvider.currentContext().modelContext(), dataTreeCandidates, now, - getLeafNodesOnly(), isSkipNotificationData(), getChangedLeafNodesOnly()); + getLeafNodesOnly(), isSkipNotificationData(), getChangedLeafNodesOnly(), getChildNodesOnly()); } catch (final Exception e) { LOG.error("Failed to process notification {}", dataTreeCandidates.stream().map(Object::toString).collect(Collectors.joining(",")), e); diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLDataTreeCandidateFormatter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLDataTreeCandidateFormatter.java index 34363b16cd..1d16ce3d72 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLDataTreeCandidateFormatter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLDataTreeCandidateFormatter.java @@ -46,8 +46,8 @@ public final class XMLDataTreeCandidateFormatter extends DataTreeCandidateFormat @Override String createText(final EffectiveModelContext schemaContext, final Collection input, - final Instant now, final boolean leafNodesOnly, final boolean skipData, - final boolean changedLeafNodesOnly) throws Exception { + final Instant now, final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly, + final boolean childNodeOnly) throws Exception { final var writer = new StringWriter(); boolean nonEmpty = false; try { @@ -58,7 +58,8 @@ public final class XMLDataTreeCandidateFormatter extends DataTreeCandidateFormat final var serializer = new XmlDataTreeCandidateSerializer(schemaContext, xmlStreamWriter); for (var candidate : input) { - nonEmpty |= serializer.serialize(candidate, leafNodesOnly, skipData, changedLeafNodesOnly); + nonEmpty |= serializer.serialize(candidate, leafNodesOnly, skipData, changedLeafNodesOnly, + childNodeOnly); } // data-changed-notification diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLNotificationFormatter.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLNotificationFormatter.java index 1e1a04e62b..ca00050c7c 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLNotificationFormatter.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XMLNotificationFormatter.java @@ -42,8 +42,8 @@ final class XMLNotificationFormatter extends NotificationFormatter { @Override String createText(final EffectiveModelContext schemaContext, final DOMNotification input, final Instant now, - final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly) - throws IOException { + final boolean leafNodesOnly, final boolean skipData, final boolean changedLeafNodesOnly, + final boolean childNodesOnly) throws IOException { final var writer = new StringWriter(); try { diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriterTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriterTest.java index 22543d1344..834deec89b 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriterTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/monitoring/CapabilitiesWriterTest.java @@ -31,6 +31,7 @@ public class CapabilitiesWriterTest { equalTo("urn:opendaylight:params:restconf:capability:pretty-print:1.0"), equalTo("urn:opendaylight:params:restconf:capability:leaf-nodes-only:1.0"), equalTo("urn:opendaylight:params:restconf:capability:changed-leaf-nodes-only:1.0"), - equalTo("urn:opendaylight:params:restconf:capability:skip-notification-data:1.0"))); + equalTo("urn:opendaylight:params:restconf:capability:skip-notification-data:1.0"), + equalTo("urn:opendaylight:params:restconf:capability:child-nodes-only:1.0"))); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JsonNotificationListenerTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JsonNotificationListenerTest.java index 768bd51afd..0744abdfd3 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JsonNotificationListenerTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/JsonNotificationListenerTest.java @@ -164,6 +164,6 @@ public class JsonNotificationListenerTest extends AbstractNotificationListenerTe final NotificationListenerAdapter notifiAdapter = ListenersBroker.getInstance().registerNotificationListener( schemaPathNotifi, "json-stream", NotificationOutputType.JSON); return notifiAdapter.formatter() - .eventData(SCHEMA_CONTEXT, notificationData, Instant.now(), false, false, false).orElseThrow(); + .eventData(SCHEMA_CONTEXT, notificationData, Instant.now(), false, false, false, false).orElseThrow(); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java index 5dedfdcf47..24abcccef4 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java @@ -161,7 +161,7 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { final boolean leafNodesOnly, final boolean skipNotificationData) { super(path, streamName, outputType); setQueryParams(NotificationQueryParams.of(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null, - LeafNodesOnlyParam.of(leafNodesOnly), SkipNotificationDataParam.of(skipNotificationData), null)); + LeafNodesOnlyParam.of(leafNodesOnly), SkipNotificationDataParam.of(skipNotificationData), null, null)); } ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName, @@ -169,7 +169,7 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { final boolean changedLeafNodesOnly) { super(path, streamName, outputType); setQueryParams(NotificationQueryParams.of(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null, - null, null, ChangedLeafNodesOnlyParam.of(changedLeafNodesOnly))); + null, null, ChangedLeafNodesOnlyParam.of(changedLeafNodesOnly), null)); } @Override diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XmlNotificationListenerTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XmlNotificationListenerTest.java index 55aab239a7..2928898b72 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XmlNotificationListenerTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/XmlNotificationListenerTest.java @@ -171,6 +171,6 @@ public class XmlNotificationListenerTest extends AbstractNotificationListenerTes final NotificationListenerAdapter notifiAdapter = ListenersBroker.getInstance().registerNotificationListener( schemaPathNotifi, "xml-stream", NotificationOutputTypeGrouping.NotificationOutputType.XML); return notifiAdapter.formatter().eventData(SCHEMA_CONTEXT, notificationData, Instant.now(), false, - false, false).orElseThrow(); + false, false, false).orElseThrow(); } }