From 038c8957d04b4d173df4b2df2310299640a7c929 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Tue, 26 Oct 2021 10:43:37 +0200 Subject: [PATCH] Support leaf-nodes-only in RFC8040 northbound We have somehow lost (or never had) parity with bierman02 extension for this option. The code to support it is in place, but due to the legacy structure it fell off the truck in terms of parsing URIs, so it could never be activated for a request. Add the proper structure to support it again and define a capability URI to let users know it is available. JIRA: NETCONF-824 Change-Id: Ib05cc361d6bc3cc534f598276ecc84c9353f4cc2 Signed-off-by: Robert Varga --- .../nb/rfc8040/LeafNodesOnlyParam.java | 70 +++++++++++++++++++ .../nb/rfc8040/NotificationQueryParams.java | 22 +++++- .../rfc8040/databind/jaxrs/QueryParams.java | 7 +- .../handlers/SchemaContextHandler.java | 2 + .../services/impl/SubscribeToStreamUtil.java | 6 +- .../listeners/AbstractQueryParams.java | 5 +- .../handlers/SchemaContextHandlerTest.java | 1 + .../listeners/ListenerAdapterTest.java | 5 +- 8 files changed, 108 insertions(+), 10 deletions(-) create mode 100644 restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/LeafNodesOnlyParam.java diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/LeafNodesOnlyParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/LeafNodesOnlyParam.java new file mode 100644 index 0000000000..266bc24210 --- /dev/null +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/LeafNodesOnlyParam.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.nb.rfc8040; + +import java.net.URI; +import org.eclipse.jdt.annotation.NonNull; + +/** + * OpenDaylight extension parameter. When used as {@code odl-leaf-nodes-only=true}, it will instruct the listener + * streams to only emit leaf nodes. + */ +public final class LeafNodesOnlyParam implements RestconfQueryParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final String uriName = "odl-leaf-nodes-only"; + + private static final @NonNull URI CAPABILITY = + URI.create("urn:opendaylight:params:restconf:capability:leaf-nodes-only:1.0"); + private static final @NonNull LeafNodesOnlyParam FALSE = new LeafNodesOnlyParam(false); + private static final @NonNull LeafNodesOnlyParam TRUE = new LeafNodesOnlyParam(true); + + private final boolean value; + + private LeafNodesOnlyParam(final boolean value) { + this.value = value; + } + + public static @NonNull LeafNodesOnlyParam of(final boolean value) { + return value ? TRUE : FALSE; + } + + public static @NonNull LeafNodesOnlyParam forUriValue(final String uriValue) { + switch (uriValue) { + case "false": + return FALSE; + case "true": + return TRUE; + default: + throw new IllegalArgumentException("Value can be 'false' or 'true', not '" + uriValue + "'"); + } + } + + @Override + public Class<@NonNull LeafNodesOnlyParam> javaClass() { + return LeafNodesOnlyParam.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/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java index 1894198761..680057d2b5 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/NotificationQueryParams.java @@ -20,23 +20,27 @@ import org.opendaylight.yangtools.concepts.Immutable; */ public final class NotificationQueryParams implements Immutable { private final SkipNotificationDataParam skipNotificationData; + private final LeafNodesOnlyParam leafNodesOnly; private final StartTimeParam startTime; private final StopTimeParam stopTime; private final FilterParam filter; private NotificationQueryParams(final StartTimeParam startTime, final StopTimeParam stopTime, - final FilterParam filter, final SkipNotificationDataParam skipNotificationData) { + final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly, + final SkipNotificationDataParam skipNotificationData) { this.startTime = startTime; this.stopTime = stopTime; this.filter = filter; + this.leafNodesOnly = leafNodesOnly; this.skipNotificationData = skipNotificationData; } public static @NonNull NotificationQueryParams of(final StartTimeParam startTime, final StopTimeParam stopTime, - final FilterParam filter, final SkipNotificationDataParam skipNotificationData) { + final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly, + final SkipNotificationDataParam skipNotificationData) { checkArgument(stopTime == null || startTime != null, "Stop-time parameter has to be used with start-time parameter."); - return new NotificationQueryParams(startTime, stopTime, filter, skipNotificationData); + return new NotificationQueryParams(startTime, stopTime, filter, leafNodesOnly, skipNotificationData); } /** @@ -66,6 +70,15 @@ public final class NotificationQueryParams implements Immutable { return filter; } + /** + * Get odl-leaf-nodes-only query parameter. + * + * @return odl-leaf-nodes-only + */ + public @Nullable LeafNodesOnlyParam leafNodesOnly() { + return leafNodesOnly; + } + /** * Get odl-skip-notification-data query parameter. * @@ -87,6 +100,9 @@ public final class NotificationQueryParams implements Immutable { if (filter != null) { helper.add("filter", filter.paramValue()); } + if (leafNodesOnly != null) { + helper.add("leafNodesOnly", leafNodesOnly.value()); + } if (skipNotificationData != null) { helper.add("skipNotificationData", skipNotificationData.value()); } diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java index 7788d69579..4848b11e97 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java @@ -29,6 +29,7 @@ import org.opendaylight.restconf.nb.rfc8040.DepthParam; import org.opendaylight.restconf.nb.rfc8040.FieldsParam; import org.opendaylight.restconf.nb.rfc8040.FilterParam; import org.opendaylight.restconf.nb.rfc8040.InsertParam; +import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam; import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams; import org.opendaylight.restconf.nb.rfc8040.PointParam; import org.opendaylight.restconf.nb.rfc8040.ReadDataParams; @@ -68,6 +69,7 @@ public final class QueryParams { StartTimeParam startTime = null; StopTimeParam stopTime = null; FilterParam filter = null; + LeafNodesOnlyParam leafNodesOnly = null; SkipNotificationDataParam skipNotificationData = null; for (Entry> entry : uriInfo.getQueryParameters().entrySet()) { @@ -85,6 +87,9 @@ public final class QueryParams { case StopTimeParam.uriName: stopTime = optionalParam(StopTimeParam::forUriValue, paramName, paramValues); break; + case LeafNodesOnlyParam.uriName: + leafNodesOnly = optionalParam(LeafNodesOnlyParam::forUriValue, paramName, paramValues); + break; case SkipNotificationDataParam.uriName: skipNotificationData = optionalParam(SkipNotificationDataParam::forUriValue, paramName, paramValues); @@ -99,7 +104,7 @@ public final class QueryParams { } try { - return NotificationQueryParams.of(startTime, stopTime, filter, skipNotificationData); + return NotificationQueryParams.of(startTime, stopTime, filter, leafNodesOnly, skipNotificationData); } catch (IllegalArgumentException e) { throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e); } diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandler.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandler.java index f36bf96aec..495eb9e340 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandler.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandler.java @@ -32,6 +32,7 @@ import org.opendaylight.restconf.nb.rfc8040.AbstractReplayParam; import org.opendaylight.restconf.nb.rfc8040.DepthParam; import org.opendaylight.restconf.nb.rfc8040.FieldsParam; import org.opendaylight.restconf.nb.rfc8040.FilterParam; +import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam; import org.opendaylight.restconf.nb.rfc8040.Rfc8040.IetfYangLibrary; import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam; import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam; @@ -184,6 +185,7 @@ public class SchemaContextHandler implements EffectiveModelContextListener, Auto .withChildValue(FilterParam.capabilityUri().toString()) .withChildValue(AbstractReplayParam.capabilityUri().toString()) .withChildValue(WithDefaultsParam.capabilityUri().toString()) + .withChildValue(LeafNodesOnlyParam.capabilityUri().toString()) .withChildValue(SkipNotificationDataParam.capabilityUri().toString()) .build()) .build()) diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/SubscribeToStreamUtil.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/SubscribeToStreamUtil.java index 3a6afed996..b95059beb5 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/SubscribeToStreamUtil.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/SubscribeToStreamUtil.java @@ -135,7 +135,8 @@ abstract class SubscribeToStreamUtil { notificationQueryParams.startTime(), notificationQueryParams.stopTime(), notificationQueryParams.filter(), - false, notificationQueryParams.skipNotificationData()); + notificationQueryParams.leafNodesOnly(), + notificationQueryParams.skipNotificationData()); final DOMDataBroker dataBroker = handlersHolder.getDataBroker(); notificationListenerAdapter.setCloseVars(dataBroker, handlersHolder.getSchemaHandler()); final MapEntryNode mapToStreams = RestconfMappingNodeUtil.mapYangNotificationStreamByIetfRestconfMonitoring( @@ -187,7 +188,8 @@ abstract class SubscribeToStreamUtil { notificationQueryParams.startTime(), notificationQueryParams.stopTime(), notificationQueryParams.filter(), - false, notificationQueryParams.skipNotificationData()); + notificationQueryParams.leafNodesOnly(), + notificationQueryParams.skipNotificationData()); final DOMDataBroker dataBroker = handlersHolder.getDataBroker(); final SchemaContextHandler schemaHandler = handlersHolder.getSchemaHandler(); diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractQueryParams.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractQueryParams.java index 2d9f2c1181..25265cf80c 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractQueryParams.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/AbstractQueryParams.java @@ -18,6 +18,7 @@ import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.nb.rfc8040.FilterParam; +import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam; import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam; import org.opendaylight.restconf.nb.rfc8040.StartTimeParam; import org.opendaylight.restconf.nb.rfc8040.StopTimeParam; @@ -57,11 +58,11 @@ abstract class AbstractQueryParams extends AbstractNotificationsData { */ @SuppressWarnings("checkstyle:hiddenField") public final void setQueryParams(final StartTimeParam startTime, final StopTimeParam stopTime, - final FilterParam filter, final boolean leafNodesOnly, + final FilterParam filter, final LeafNodesOnlyParam leafNodesOnly, final SkipNotificationDataParam skipNotificationData) { start = startTime == null ? Instant.now() : parseDateAndTime(startTime.value()); stop = stopTime == null ? null : parseDateAndTime(stopTime.value()); - this.leafNodesOnly = leafNodesOnly; + this.leafNodesOnly = leafNodesOnly == null ? false : leafNodesOnly.value(); this.skipNotificationData = skipNotificationData == null ? false : skipNotificationData.value(); if (filter != null) { diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandlerTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandlerTest.java index e04a3a8275..68b40980e6 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandlerTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/handlers/SchemaContextHandlerTest.java @@ -154,6 +154,7 @@ public class SchemaContextHandlerTest { equalTo("urn:ietf:params:restconf:capability:filter:1.0"), equalTo("urn:ietf:params:restconf:capability:replay:1.0"), equalTo("urn:ietf:params:restconf:capability:with-defaults:1.0"), + equalTo("urn:opendaylight:params:restconf:capability:leaf-nodes-only:1.0"), equalTo("urn:opendaylight:params:restconf:capability:skip-notification-data:1.0"))); } diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java index 13fa69cef1..7083a1a9a7 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/streams/listeners/ListenerAdapterTest.java @@ -34,6 +34,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.mdsal.dom.api.DOMSchemaService; +import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam; import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam; import org.opendaylight.restconf.nb.rfc8040.StartTimeParam; import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler; @@ -121,8 +122,8 @@ public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest { final NotificationOutputTypeGrouping.NotificationOutputType outputType, final boolean leafNodesOnly, final boolean skipNotificationData) { super(path, streamName, outputType); - setQueryParams(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null, leafNodesOnly, - SkipNotificationDataParam.of(skipNotificationData)); + setQueryParams(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null, + LeafNodesOnlyParam.of(leafNodesOnly), SkipNotificationDataParam.of(skipNotificationData)); } @Override -- 2.36.6