From e82bc31b6eb203446c174798fe8441f712fe7361 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Sat, 16 Sep 2023 11:24:35 +0200 Subject: [PATCH] Create MdsalRestconfServer The actual binding to MD-SAL services is independent of other concerns, just as JAX-RS binding. Introduce MdsalRestconfServer to act as an intermediary. This allows us to centralize data binding operations and later act as the central implementation dispatch. This reduces the number of callers to InstanceIdentifierParser.toInstanceIdentifier(), as we have a proper indirection to bind either the root or a non-empty identifier and can provide the first cut of differentiated binding. In RestconfOperationsServiceImpl this has the nice effect of bringing together the two distinct invocation paths, leading to OperationsContent.bodyFor(EffectiveModelContext) being redundant. In RestconfDataServiceImpl we lose getRestconfStrategy(), which is now invoked on the server. We also clarify variable names, so they have a semantic meaning. RestconfInvokeOperationsServiceImpl integration sees RestconfStrategy grow awareness of DOMRpcService, providing a clean invocation interface centered around RestconfFuture>. That co-location of concerns also allow us to perform only a single error mapping, we any DOMRpcResult's errors into a RestconfDocumentedException. JIRA: NETCONF-1157 Change-Id: I9ecefb2e065b4ad6ed8e4226713da851a1050619 Signed-off-by: Robert Varga --- .../restconf/nb/rfc8040/JaxRsNorthbound.java | 11 +- .../nb/rfc8040/RestconfApplication.java | 26 ++- .../rests/services/impl/CreateStreamUtil.java | 19 +- .../services/impl/MdsalRestconfServer.java | 112 +++++++++ .../services/impl/OperationsContent.java | 16 -- .../impl/RestconfDataServiceImpl.java | 216 ++++++++---------- .../RestconfInvokeOperationsServiceImpl.java | 130 ++++------- .../impl/RestconfOperationsServiceImpl.java | 25 +- .../transactions/MdsalRestconfStrategy.java | 7 +- .../transactions/NetconfRestconfStrategy.java | 6 +- .../rests/transactions/RestconfStrategy.java | 51 ++++- .../services/impl/CreateStreamUtilTest.java | 10 +- .../impl/MdsalRestconfServerTest.java | 90 ++++++++ .../rests/services/impl/Netconf799Test.java | 7 +- .../rests/services/impl/Netconf822Test.java | 19 +- .../impl/RestconfDataServiceImplTest.java | 21 +- ...stconfInvokeOperationsServiceImplTest.java | 106 +++++---- .../RestconfOperationsServiceImplTest.java | 10 +- .../MdsalRestconfStrategyTest.java | 69 +++--- .../NetconfRestconfStrategyTest.java | 62 ++--- 20 files changed, 596 insertions(+), 417 deletions(-) create mode 100644 restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java create mode 100644 restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServerTest.java diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/JaxRsNorthbound.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/JaxRsNorthbound.java index 05967718f7..901ea211eb 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/JaxRsNorthbound.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/JaxRsNorthbound.java @@ -31,6 +31,7 @@ import org.opendaylight.mdsal.dom.api.DOMNotificationService; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider; +import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.MdsalRestconfServer; import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfDataStreamServiceImpl; import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; import org.opendaylight.restconf.nb.rfc8040.streams.WebSocketInitializer; @@ -79,9 +80,9 @@ public final class JaxRsNorthbound implements AutoCloseable { @Reference final DOMMountPointService mountPointService, @Reference final DOMNotificationService notificationService, @Reference final DOMRpcService rpcService, @Reference final DOMSchemaService schemaService, @Reference final DatabindProvider databindProvider, - final Configuration configuration) throws ServletException { + @Reference final MdsalRestconfServer server, final Configuration configuration) throws ServletException { this(webServer, webContextSecurer, servletSupport, filterAdapterConfiguration, actionService, dataBroker, - mountPointService, notificationService, rpcService, schemaService, databindProvider, + mountPointService, notificationService, rpcService, schemaService, databindProvider, server, configuration.ping$_$executor$_$name$_$prefix(), configuration.max$_$thread$_$count(), new StreamsConfiguration(configuration.maximum$_$fragment$_$length(), configuration.idle$_$timeout(), configuration.heartbeat$_$interval(), configuration.use$_$sse())); @@ -92,7 +93,7 @@ public final class JaxRsNorthbound implements AutoCloseable { final DOMActionService actionService, final DOMDataBroker dataBroker, final DOMMountPointService mountPointService, final DOMNotificationService notificationService, final DOMRpcService rpcService, final DOMSchemaService schemaService, - final DatabindProvider databindProvider, + final DatabindProvider databindProvider, final MdsalRestconfServer server, final String pingNamePrefix, final int pingMaxThreadCount, final StreamsConfiguration streamsConfiguration) throws ServletException { final var scheduledThreadPool = new ScheduledThreadPoolWrapper(pingMaxThreadCount, @@ -105,8 +106,8 @@ public final class JaxRsNorthbound implements AutoCloseable { .addServlet(ServletDetails.builder() .addUrlPattern("/*") .servlet(servletSupport.createHttpServletBuilder( - new RestconfApplication(databindProvider, mountPointService, dataBroker, rpcService, actionService, - notificationService, schemaService, streamsConfiguration)) + new RestconfApplication(databindProvider, server, mountPointService, dataBroker, rpcService, + actionService, notificationService, schemaService, streamsConfiguration)) .build()) .asyncSupported(true) .build()) diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfApplication.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfApplication.java index 805eff2ae4..9b8b88d262 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfApplication.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfApplication.java @@ -18,6 +18,7 @@ import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider; import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService; +import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.MdsalRestconfServer; import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfDataServiceImpl; import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfImpl; import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.RestconfInvokeOperationsServiceImpl; @@ -28,29 +29,30 @@ import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; @Singleton public class RestconfApplication extends AbstractRestconfApplication { - private RestconfApplication(final DatabindProvider databindProvider, final DOMMountPointService mountPointService, + private RestconfApplication(final DatabindProvider databindProvider, final MdsalRestconfServer server, + final DOMMountPointService mountPointService, final RestconfStreamsSubscriptionService streamSubscription, final DOMDataBroker dataBroker, - final DOMRpcService rpcService, final DOMActionService actionService, - final DOMNotificationService notificationService, final DOMSchemaService domSchemaService, - final StreamsConfiguration configuration) { + final DOMActionService actionService, final DOMNotificationService notificationService, + final DOMSchemaService domSchemaService, final StreamsConfiguration configuration) { super(databindProvider, List.of( streamSubscription, - new RestconfDataServiceImpl(databindProvider, dataBroker, mountPointService, streamSubscription, - actionService, configuration), - new RestconfInvokeOperationsServiceImpl(databindProvider, rpcService, mountPointService, configuration), - new RestconfOperationsServiceImpl(databindProvider, mountPointService), + new RestconfDataServiceImpl(databindProvider, server, dataBroker, streamSubscription, actionService, + configuration), + new RestconfInvokeOperationsServiceImpl(databindProvider, server, mountPointService, configuration), + new RestconfOperationsServiceImpl(databindProvider, server), new RestconfSchemaServiceImpl(domSchemaService, mountPointService), new RestconfImpl(databindProvider))); } @Inject - public RestconfApplication(final DatabindProvider databindProvider, final DOMMountPointService mountPointService, - final DOMDataBroker dataBroker, final DOMRpcService rpcService, final DOMActionService actionService, + public RestconfApplication(final DatabindProvider databindProvider, final MdsalRestconfServer server, + final DOMMountPointService mountPointService, final DOMDataBroker dataBroker, + final DOMRpcService rpcService, final DOMActionService actionService, final DOMNotificationService notificationService, final DOMSchemaService domSchemaService, final StreamsConfiguration configuration) { - this(databindProvider, mountPointService, + this(databindProvider, server, mountPointService, new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService, databindProvider, configuration), - dataBroker, rpcService, actionService, notificationService, domSchemaService, configuration); + dataBroker, actionService, notificationService, domSchemaService, configuration); } } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtil.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtil.java index 8e5502928b..d94ea1e47a 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtil.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtil.java @@ -18,7 +18,6 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.api.DOMNotificationService; import org.opendaylight.mdsal.dom.api.DOMRpcResult; import org.opendaylight.mdsal.dom.api.DOMSchemaService; -import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants; import org.opendaylight.restconf.nb.rfc8040.streams.listeners.DeviceNotificationListenerAdaptor; @@ -108,7 +107,7 @@ final class CreateStreamUtil { * */ // FIXME: this really should be a normal RPC implementation - static DOMRpcResult createDataChangeNotifiStream(final ListenersBroker listenersBroker, final ContainerNode input, + static ContainerNode createDataChangeNotifiStream(final ListenersBroker listenersBroker, final ContainerNode input, final EffectiveModelContext refSchemaCtx) { // parsing out of container with settings and path final YangInstanceIdentifier path = preparePath(input); @@ -126,10 +125,10 @@ final class CreateStreamUtil { listenersBroker.registerDataChangeListener(path, streamName, outputType); // building of output - return new DefaultDOMRpcResult(Builders.containerBuilder() + return Builders.containerBuilder() .withNodeIdentifier(SAL_REMOTE_OUTPUT_NODEID) .withChild(ImmutableNodes.leafNode(STREAM_NAME_NODEID, streamName)) - .build()); + .build(); } /** @@ -141,7 +140,8 @@ final class CreateStreamUtil { * @param mountPointService dom mount point service * @return {@link DOMRpcResult} - Output of RPC - example in JSON */ - static DOMRpcResult createDeviceNotificationListener(final String baseUrl, final ContainerNode input, + // FIXME: this should be an RPC invocation + static ContainerNode createDeviceNotificationListener(final String baseUrl, final ContainerNode input, final SubscribeToStreamUtil streamUtil, final DOMMountPointService mountPointService) { // parsing out of container with settings and path // FIXME: ugly cast @@ -187,12 +187,11 @@ final class CreateStreamUtil { mountPointService, mountPoint.getIdentifier()); notificationListenerAdapter.listen(mountNotifService, notificationPaths); - // building of output - return new DefaultDOMRpcResult(Builders.containerBuilder() + return Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(SubscribeDeviceNotificationOutput.QNAME)) - .withChild(ImmutableNodes.leafNode(DEVICE_NOTIFICATION_STREAM_PATH, baseUrl + deviceName - + "?" + RestconfStreamsConstants.NOTIFICATION_TYPE + "=" + RestconfStreamsConstants.DEVICE)) - .build()); + .withChild(ImmutableNodes.leafNode(DEVICE_NOTIFICATION_STREAM_PATH, baseUrl + deviceName + "?" + + RestconfStreamsConstants.NOTIFICATION_TYPE + "=" + RestconfStreamsConstants.DEVICE)) + .build(); } /** diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java new file mode 100644 index 0000000000..efa0b9bfbe --- /dev/null +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 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.rests.services.impl; + +import static com.google.common.base.Verify.verifyNotNull; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.VisibleForTesting; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import javax.inject.Inject; +import javax.inject.Singleton; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMRpcService; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; +import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext; +import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy; +import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy; +import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A RESTCONF server implemented on top of MD-SAL. + */ +// FIXME: factor out the 'RestconfServer' interface once we're ready +// FIXME: this should live in 'org.opendaylight.restconf.server.mdsal' package +@Singleton +@Component(service = MdsalRestconfServer.class) +public final class MdsalRestconfServer { + private static final Logger LOG = LoggerFactory.getLogger(MdsalRestconfServer.class); + private static final VarHandle LOCAL_STRATEGY; + + static { + try { + LOCAL_STRATEGY = MethodHandles.lookup() + .findVarHandle(MdsalRestconfServer.class, "localStrategy", RestconfStrategy.class); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new ExceptionInInitializerError(e); + } + } + + private final @NonNull DOMMountPointService mountPointService; + private final @NonNull DOMDataBroker dataBroker; + private final @Nullable DOMRpcService rpcService; + + @SuppressWarnings("unused") + private volatile RestconfStrategy localStrategy; + + @Inject + @Activate + public MdsalRestconfServer(@Reference final DOMDataBroker dataBroker, @Reference final DOMRpcService rpcService, + @Reference final DOMMountPointService mountPointService) { + this.dataBroker = requireNonNull(dataBroker); + this.rpcService = requireNonNull(rpcService); + this.mountPointService = requireNonNull(mountPointService); + } + + @NonNull InstanceIdentifierContext bindRequestPath(final DatabindContext databind, final String identifier) { + // FIXME: go through ApiPath first. That part should eventually live in callers + // FIXME: DatabindContext looks like it should be internal + return verifyNotNull(ParserIdentifier.toInstanceIdentifier(requireNonNull(identifier), databind.modelContext(), + mountPointService)); + } + + @SuppressWarnings("static-method") + @NonNull InstanceIdentifierContext bindRequestRoot(final DatabindContext databind) { + return InstanceIdentifierContext.ofLocalRoot(databind.modelContext()); + } + + @VisibleForTesting + @NonNull RestconfStrategy getRestconfStrategy(final EffectiveModelContext modelContext, + final @Nullable DOMMountPoint mountPoint) { + if (mountPoint == null) { + return localStrategy(modelContext); + } + + final var ret = RestconfStrategy.forMountPoint(modelContext, mountPoint); + if (ret == null) { + final var mountId = mountPoint.getIdentifier(); + LOG.warn("Mount point {} does not expose a suitable access interface", mountId); + throw new RestconfDocumentedException("Could not find a supported access interface in mount point " + + mountId); + } + return ret; + } + + private @NonNull RestconfStrategy localStrategy(final EffectiveModelContext modelContext) { + final var local = (RestconfStrategy) LOCAL_STRATEGY.getAcquire(this); + if (local != null && modelContext.equals(local.modelContext())) { + return local; + } + + final var created = new MdsalRestconfStrategy(modelContext, dataBroker, rpcService); + LOCAL_STRATEGY.setRelease(this, created); + return created; + } +} diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java index 356fbae483..51e9c4ff1e 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java @@ -96,22 +96,6 @@ enum OperationsContent { this.emptyBody = requireNonNull(emptyBody); } - /** - * Return the content for a particular {@link EffectiveModelContext}. - * - * @param context Context to use - * @return Content of HTTP GET operation as a String - */ - public final @NonNull String bodyFor(final EffectiveModelContext context) { - if (isEmptyContext(context)) { - // No modules, or defensive return empty content - return emptyBody; - } - - final var moduleRpcs = getModuleRpcs(context, context.getModuleStatements()); - return moduleRpcs.isEmpty() ? emptyBody : createBody(moduleRpcs); - } - /** * Return content with RPCs and actions for a particular {@link Inference}. * diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImpl.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImpl.java index 7e7244ea6f..4d00582d33 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImpl.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImpl.java @@ -22,13 +22,13 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import java.io.IOException; import java.io.InputStream; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.net.URI; import java.time.Clock; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import javax.ws.rs.Consumes; @@ -58,12 +58,12 @@ import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier; import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteOperations; import org.opendaylight.mdsal.dom.api.DOMMountPoint; -import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.common.patch.PatchContext; import org.opendaylight.restconf.common.patch.PatchStatusContext; import org.opendaylight.restconf.nb.rfc8040.MediaTypes; +import org.opendaylight.restconf.nb.rfc8040.ReadDataParams; import org.opendaylight.restconf.nb.rfc8040.databind.ChildBody; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider; import org.opendaylight.restconf.nb.rfc8040.databind.JsonChildBody; @@ -82,14 +82,11 @@ import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; import org.opendaylight.restconf.nb.rfc8040.monitoring.RestconfStateStreams; import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService; -import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy; -import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy; import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants; import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker; import org.opendaylight.restconf.nb.rfc8040.streams.listeners.NotificationListenerAdapter; import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec; -import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType; import org.opendaylight.yangtools.yang.common.Empty; import org.opendaylight.yangtools.yang.common.ErrorTag; @@ -119,35 +116,22 @@ import org.slf4j.LoggerFactory; public final class RestconfDataServiceImpl { private static final Logger LOG = LoggerFactory.getLogger(RestconfDataServiceImpl.class); private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MMM-dd HH:mm:ss"); - private static final VarHandle LOCAL_STRATEGY; - - static { - try { - LOCAL_STRATEGY = MethodHandles.lookup() - .findVarHandle(RestconfDataServiceImpl.class, "localStrategy", RestconfStrategy.class); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new ExceptionInInitializerError(e); - } - } private final RestconfStreamsSubscriptionService delegRestconfSubscrService; private final DatabindProvider databindProvider; - private final DOMMountPointService mountPointService; private final SubscribeToStreamUtil streamUtils; private final DOMActionService actionService; + private final MdsalRestconfServer server; + @Deprecated(forRemoval = true) private final DOMDataBroker dataBroker; private final ListenersBroker listenersBroker = ListenersBroker.getInstance(); - @SuppressWarnings("unused") - private volatile RestconfStrategy localStrategy; - - public RestconfDataServiceImpl(final DatabindProvider databindProvider, - final DOMDataBroker dataBroker, final DOMMountPointService mountPointService, - final RestconfStreamsSubscriptionService delegRestconfSubscrService, + public RestconfDataServiceImpl(final DatabindProvider databindProvider, final MdsalRestconfServer server, + final DOMDataBroker dataBroker, final RestconfStreamsSubscriptionService delegRestconfSubscrService, final DOMActionService actionService, final StreamsConfiguration configuration) { this.databindProvider = requireNonNull(databindProvider); + this.server = requireNonNull(server); this.dataBroker = requireNonNull(dataBroker); - this.mountPointService = requireNonNull(mountPointService); this.delegRestconfSubscrService = requireNonNull(delegRestconfSubscrService); this.actionService = requireNonNull(actionService); streamUtils = configuration.useSSE() ? SubscribeToStreamUtil.serverSentEvents() @@ -170,7 +154,8 @@ public final class RestconfDataServiceImpl { MediaType.TEXT_XML }) public Response readData(@Context final UriInfo uriInfo) { - return readData(null, uriInfo); + final var readParams = QueryParams.newReadDataParams(uriInfo); + return readData(server.bindRequestRoot(databindProvider.currentContext()), readParams).getValue(); } /** @@ -192,11 +177,10 @@ public final class RestconfDataServiceImpl { public Response readData(@Encoded @PathParam("identifier") final String identifier, @Context final UriInfo uriInfo) { final var readParams = QueryParams.newReadDataParams(uriInfo); - final var schemaContextRef = databindProvider.currentContext().modelContext(); - // FIXME: go through - final var instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier, schemaContextRef, - mountPointService); - final var mountPoint = instanceIdentifier.getMountPoint(); + final var databind = databindProvider.currentContext(); + final var schemaContextRef = databind.modelContext(); + final var reqPath = server.bindRequestPath(databind, identifier); + final var mountPoint = reqPath.getMountPoint(); // FIXME: this looks quite crazy, why do we even have it? if (mountPoint == null && identifier != null && identifier.contains(STREAMS_PATH) @@ -204,46 +188,52 @@ public final class RestconfDataServiceImpl { createAllYangNotificationStreams(schemaContextRef, uriInfo); } - final var queryParams = QueryParams.newQueryParameters(readParams, instanceIdentifier); - final var fieldPaths = queryParams.fieldPaths(); - // FIXME:the model context should be coming from instanceIdentifier! - final var strategy = getRestconfStrategy(schemaContextRef, mountPoint); - final NormalizedNode node; - if (fieldPaths != null && !fieldPaths.isEmpty()) { - node = strategy.readData(readParams.content(), instanceIdentifier.getInstanceIdentifier(), - readParams.withDefaults(), fieldPaths); - } else { - node = strategy.readData(readParams.content(), instanceIdentifier.getInstanceIdentifier(), - readParams.withDefaults()); - } + final var nodeAndResponse = readData(reqPath, readParams); // FIXME: this is utter craziness, refactor it properly! if (identifier != null && identifier.contains(STREAM_PATH) && identifier.contains(STREAM_ACCESS_PATH_PART) && identifier.contains(STREAM_LOCATION_PATH_PART)) { - final String value = (String) node.body(); + final String value = (String) nodeAndResponse.getKey().body(); final String streamName = value.substring(value.indexOf(NOTIFICATION_STREAM + '/')); delegRestconfSubscrService.subscribeToStream(streamName, uriInfo); } + + return nodeAndResponse.getValue(); + } + + private Entry readData(final InstanceIdentifierContext reqPath, + final ReadDataParams readParams) { + final var queryParams = QueryParams.newQueryParameters(readParams, reqPath); + final var fieldPaths = queryParams.fieldPaths(); + final var strategy = server.getRestconfStrategy(reqPath.getSchemaContext(), reqPath.getMountPoint()); + final NormalizedNode node; + if (fieldPaths != null && !fieldPaths.isEmpty()) { + node = strategy.readData(readParams.content(), reqPath.getInstanceIdentifier(), + readParams.withDefaults(), fieldPaths); + } else { + node = strategy.readData(readParams.content(), reqPath.getInstanceIdentifier(), + readParams.withDefaults()); + } if (node == null) { throw new RestconfDocumentedException( "Request could not be completed because the relevant data model content does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING); } - return switch (readParams.content()) { + return Map.entry(node, switch (readParams.content()) { case ALL, CONFIG -> { final QName type = node.name().getNodeType(); yield Response.status(Status.OK) - .entity(new NormalizedNodePayload(instanceIdentifier.inference(), node, queryParams)) + .entity(new NormalizedNodePayload(reqPath.inference(), node, queryParams)) .header("ETag", '"' + type.getModule().getRevision().map(Revision::toString).orElse(null) + "-" + type.getLocalName() + '"') .header("Last-Modified", FORMATTER.format(LocalDateTime.now(Clock.systemUTC()))) .build(); } case NONCONFIG -> Response.status(Status.OK) - .entity(new NormalizedNodePayload(instanceIdentifier.inference(), node, queryParams)) + .entity(new NormalizedNodePayload(reqPath.inference(), node, queryParams)) .build(); - }; + }); } private void createAllYangNotificationStreams(final EffectiveModelContext schemaContext, final UriInfo uriInfo) { @@ -382,10 +372,9 @@ public final class RestconfDataServiceImpl { } private Response putData(final @Nullable String identifier, final UriInfo uriInfo, final ResourceBody body) { - final var localModel = databindProvider.currentContext().modelContext(); - final var context = ParserIdentifier.toInstanceIdentifier(identifier, localModel, mountPointService); - final var insert = QueryParams.parseInsert(context.getSchemaContext(), uriInfo); - final var req = bindResourceRequest(context, body); + final var reqPath = server.bindRequestPath(databindProvider.currentContext(), identifier); + final var insert = QueryParams.parseInsert(reqPath.getSchemaContext(), uriInfo); + final var req = bindResourceRequest(reqPath, body); return switch ( req.strategy().putData(req.path(), req.data(), insert)) { @@ -430,17 +419,16 @@ public final class RestconfDataServiceImpl { }) public Response postDataJSON(@Encoded @PathParam("identifier") final String identifier, final InputStream body, @Context final UriInfo uriInfo) { - final var instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier, - databindProvider.currentContext().modelContext(), mountPointService); - if (instanceIdentifier.getSchemaNode() instanceof ActionDefinition) { + final var reqPath = server.bindRequestPath(databindProvider.currentContext(), identifier); + if (reqPath.getSchemaNode() instanceof ActionDefinition) { try (var jsonBody = new JsonOperationInputBody(body)) { - return invokeAction(instanceIdentifier, jsonBody); + return invokeAction(reqPath, jsonBody); } } try (var jsonBody = new JsonChildBody(body)) { - return postData(instanceIdentifier.inference(), instanceIdentifier.getInstanceIdentifier(), jsonBody, - uriInfo, instanceIdentifier.getMountPoint()); + return postData(reqPath.inference(), reqPath.getInstanceIdentifier(), jsonBody, uriInfo, + reqPath.getMountPoint()); } } @@ -481,16 +469,16 @@ public final class RestconfDataServiceImpl { }) public Response postDataXML(@Encoded @PathParam("identifier") final String identifier, final InputStream body, @Context final UriInfo uriInfo) { - final var iid = ParserIdentifier.toInstanceIdentifier(identifier, - databindProvider.currentContext().modelContext(), mountPointService); - if (iid.getSchemaNode() instanceof ActionDefinition) { + final var reqPath = server.bindRequestPath(databindProvider.currentContext(), identifier); + if (reqPath.getSchemaNode() instanceof ActionDefinition) { try (var xmlBody = new XmlOperationInputBody(body)) { - return invokeAction(iid, xmlBody); + return invokeAction(reqPath, xmlBody); } } try (var xmlBody = new XmlChildBody(body)) { - return postData(iid.inference(), iid.getInstanceIdentifier(), xmlBody, uriInfo, iid.getMountPoint()); + return postData(reqPath.inference(), reqPath.getInstanceIdentifier(), xmlBody, uriInfo, + reqPath.getMountPoint()); } } @@ -503,7 +491,7 @@ public final class RestconfDataServiceImpl { final UriInfo uriInfo, final @Nullable DOMMountPoint mountPoint) { final var modelContext = inference.getEffectiveModelContext(); final var insert = QueryParams.parseInsert(modelContext, uriInfo); - final var strategy = getRestconfStrategy(modelContext, mountPoint); + final var strategy = server.getRestconfStrategy(modelContext, mountPoint); var path = parentPath; final var payload = body.toPayload(path, inference); final var data = payload.body(); @@ -547,12 +535,10 @@ public final class RestconfDataServiceImpl { @Path("/data/{identifier:.+}") public void deleteData(@Encoded @PathParam("identifier") final String identifier, @Suspended final AsyncResponse ar) { - final var instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier, - databindProvider.currentContext().modelContext(), mountPointService); - final var strategy = getRestconfStrategy(instanceIdentifier.getSchemaContext(), - instanceIdentifier.getMountPoint()); + final var reqPath = server.bindRequestPath(databindProvider.currentContext(), identifier); + final var strategy = server.getRestconfStrategy(reqPath.getSchemaContext(), reqPath.getMountPoint()); - Futures.addCallback(strategy.delete(instanceIdentifier.getInstanceIdentifier()), new FutureCallback<>() { + Futures.addCallback(strategy.delete(reqPath.getInstanceIdentifier()), new FutureCallback<>() { @Override public void onSuccess(final Empty result) { ar.resume(Response.noContent().build()); @@ -581,7 +567,7 @@ public final class RestconfDataServiceImpl { }) public void plainPatchDataXML(final InputStream body, @Suspended final AsyncResponse ar) { try (var xmlBody = new XmlResourceBody(body)) { - plainPatchData(null, xmlBody, ar); + plainPatchData(xmlBody, ar); } } @@ -622,7 +608,7 @@ public final class RestconfDataServiceImpl { }) public void plainPatchDataJSON(final InputStream body, @Suspended final AsyncResponse ar) { try (var jsonBody = new JsonResourceBody(body)) { - plainPatchData(null, jsonBody, ar); + plainPatchData(jsonBody, ar); } } @@ -647,6 +633,17 @@ public final class RestconfDataServiceImpl { } } + /** + * Partially modify the target data resource, as defined in + * RFC8040, section 4.6.1. + * + * @param body data node for put to config DS + * @param ar {@link AsyncResponse} which needs to be completed + */ + private void plainPatchData(final ResourceBody body, final AsyncResponse ar) { + plainPatchData(server.bindRequestRoot(databindProvider.currentContext()), body, ar); + } + /** * Partially modify the target data resource, as defined in * RFC8040, section 4.6.1. @@ -655,11 +652,21 @@ public final class RestconfDataServiceImpl { * @param body data node for put to config DS * @param ar {@link AsyncResponse} which needs to be completed */ - private void plainPatchData(final @Nullable String identifier, final ResourceBody body, final AsyncResponse ar) { - final var req = bindResourceRequest( - ParserIdentifier.toInstanceIdentifier(identifier, databindProvider.currentContext().modelContext(), - mountPointService), - body); + private void plainPatchData(final String identifier, final ResourceBody body, final AsyncResponse ar) { + plainPatchData(server.bindRequestPath(databindProvider.currentContext(), identifier), body, ar); + } + + /** + * Partially modify the target data resource, as defined in + * RFC8040, section 4.6.1. + * + * @param reqPath path to target + * @param body data node for put to config DS + * @param ar {@link AsyncResponse} which needs to be completed + */ + private void plainPatchData(final InstanceIdentifierContext reqPath, final ResourceBody body, + final AsyncResponse ar) { + final var req = bindResourceRequest(reqPath, body); final var future = req.strategy().merge(req.path(), req.data()); Futures.addCallback(future, new FutureCallback<>() { @@ -675,13 +682,14 @@ public final class RestconfDataServiceImpl { }, MoreExecutors.directExecutor()); } - private @NonNull ResourceRequest bindResourceRequest(final InstanceIdentifierContext context, + private @NonNull ResourceRequest bindResourceRequest(final InstanceIdentifierContext reqPath, final ResourceBody body) { - final var inference = context.inference(); - final var path = context.getInstanceIdentifier(); - final var data = body.toNormalizedNode(path, inference, context.getSchemaNode()); + final var inference = reqPath.inference(); + final var path = reqPath.getInstanceIdentifier(); + final var data = body.toNormalizedNode(path, inference, reqPath.getSchemaNode()); - return new ResourceRequest(getRestconfStrategy(inference.getEffectiveModelContext(), context.getMountPoint()), + return new ResourceRequest( + server.getRestconfStrategy(inference.getEffectiveModelContext(), reqPath.getMountPoint()), path, data); } @@ -775,17 +783,17 @@ public final class RestconfDataServiceImpl { } private PatchStatusContext yangPatchData(final String identifier, final @NonNull PatchBody body) { - final var iid = ParserIdentifier.toInstanceIdentifier(requireNonNull(identifier), - databindProvider.currentContext().modelContext(), mountPointService); - final var context = iid.getSchemaContext(); - return yangPatchData(context, parsePatchBody(context, iid.getInstanceIdentifier(), body), iid.getMountPoint()); + final var reqPath = server.bindRequestPath(databindProvider.currentContext(), identifier); + final var modelContext = reqPath.getSchemaContext(); + return yangPatchData(modelContext, parsePatchBody(modelContext, reqPath.getInstanceIdentifier(), body), + reqPath.getMountPoint()); } @VisibleForTesting @NonNull PatchStatusContext yangPatchData(final @NonNull EffectiveModelContext modelContext, final @NonNull PatchContext patch, final @Nullable DOMMountPoint mountPoint) { - return getRestconfStrategy(modelContext, mountPoint).patchData(patch); + return server.getRestconfStrategy(modelContext, mountPoint).patchData(patch); } private static @NonNull PatchContext parsePatchBody(final @NonNull EffectiveModelContext context, @@ -799,53 +807,25 @@ public final class RestconfDataServiceImpl { } } - @VisibleForTesting - @NonNull RestconfStrategy getRestconfStrategy(final EffectiveModelContext modelContext, - final @Nullable DOMMountPoint mountPoint) { - if (mountPoint == null) { - return localStrategy(modelContext); - } - - final var ret = RestconfStrategy.forMountPoint(modelContext, mountPoint); - if (ret == null) { - final var mountId = mountPoint.getIdentifier(); - LOG.warn("Mount point {} does not expose a suitable access interface", mountId); - throw new RestconfDocumentedException("Could not find a supported access interface in mount point " - + mountId); - } - return ret; - } - - private @NonNull RestconfStrategy localStrategy(final EffectiveModelContext modelContext) { - final var local = (RestconfStrategy) LOCAL_STRATEGY.getAcquire(this); - if (local != null && modelContext.equals(local.modelContext())) { - return local; - } - - final var created = new MdsalRestconfStrategy(modelContext, dataBroker); - LOCAL_STRATEGY.setRelease(this, created); - return created; - } - /** * Invoke Action operation. * * @param payload {@link NormalizedNodePayload} - the body of the operation * @return {@link NormalizedNodePayload} wrapped in {@link Response} */ - private Response invokeAction(final InstanceIdentifierContext context, final OperationInputBody body) { - final var yangIIdContext = context.getInstanceIdentifier(); + private Response invokeAction(final InstanceIdentifierContext reqPath, final OperationInputBody body) { + final var yangIIdContext = reqPath.getInstanceIdentifier(); final ContainerNode input; try { - input = body.toContainerNode(context.inference()); + input = body.toContainerNode(reqPath.inference()); } catch (IOException e) { LOG.debug("Error reading input", e); throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, e); } - final var mountPoint = context.getMountPoint(); - final var inference = context.inference(); + final var mountPoint = reqPath.getMountPoint(); + final var inference = reqPath.inference(); final var schemaPath = inference.toSchemaInferenceStack().toSchemaNodeIdentifier(); final var response = mountPoint != null ? invokeAction(input, schemaPath, yangIIdContext, mountPoint) : invokeAction(input, schemaPath, yangIIdContext, actionService); diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java index cbd3096855..0fc3d26c11 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java @@ -9,14 +9,12 @@ package org.opendaylight.restconf.nb.rfc8040.rests.services.impl; import static java.util.Objects.requireNonNull; -import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.io.IOException; import java.io.InputStream; -import java.util.List; +import java.util.Optional; import javax.ws.rs.Consumes; import javax.ws.rs.Encoded; import javax.ws.rs.POST; @@ -29,31 +27,23 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; -import org.eclipse.jdt.annotation.NonNull; -import org.opendaylight.mdsal.dom.api.DOMMountPoint; import org.opendaylight.mdsal.dom.api.DOMMountPointService; -import org.opendaylight.mdsal.dom.api.DOMRpcException; -import org.opendaylight.mdsal.dom.api.DOMRpcResult; -import org.opendaylight.mdsal.dom.api.DOMRpcService; -import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.restconf.common.errors.RestconfFuture; import org.opendaylight.restconf.nb.rfc8040.MediaTypes; +import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider; import org.opendaylight.restconf.nb.rfc8040.databind.JsonOperationInputBody; import org.opendaylight.restconf.nb.rfc8040.databind.OperationInputBody; import org.opendaylight.restconf.nb.rfc8040.databind.XmlOperationInputBody; +import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; -import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; import org.opendaylight.yang.gen.v1.urn.opendaylight.device.notification.rev221106.SubscribeDeviceNotification; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.remote.rev140114.CreateDataChangeEventSubscription; import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; -import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.opendaylight.yangtools.yang.common.YangConstants; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; -import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,14 +56,16 @@ public final class RestconfInvokeOperationsServiceImpl { private static final Logger LOG = LoggerFactory.getLogger(RestconfInvokeOperationsServiceImpl.class); private final DatabindProvider databindProvider; - private final DOMRpcService rpcService; + private final MdsalRestconfServer server; + @Deprecated(forRemoval = true) private final DOMMountPointService mountPointService; private final SubscribeToStreamUtil streamUtils; - public RestconfInvokeOperationsServiceImpl(final DatabindProvider databindProvider, final DOMRpcService rpcService, - final DOMMountPointService mountPointService, final StreamsConfiguration configuration) { + public RestconfInvokeOperationsServiceImpl(final DatabindProvider databindProvider, + final MdsalRestconfServer server, final DOMMountPointService mountPointService, + final StreamsConfiguration configuration) { this.databindProvider = requireNonNull(databindProvider); - this.rpcService = requireNonNull(rpcService); + this.server = requireNonNull(server); this.mountPointService = requireNonNull(mountPointService); streamUtils = configuration.useSSE() ? SubscribeToStreamUtil.serverSentEvents() : SubscribeToStreamUtil.webSockets(); @@ -140,53 +132,29 @@ public final class RestconfInvokeOperationsServiceImpl { private void invokeRpc(final String identifier, final UriInfo uriInfo, final AsyncResponse ar, final OperationInputBody body) { - final var dataBind = databindProvider.currentContext(); - final var schemaContext = dataBind.modelContext(); - final var context = ParserIdentifier.toInstanceIdentifier(identifier, schemaContext, mountPointService); + final var databind = databindProvider.currentContext(); + final var reqPath = server.bindRequestPath(databind, identifier); final ContainerNode input; try { - input = body.toContainerNode(context.inference()); + input = body.toContainerNode(reqPath.inference()); } catch (IOException e) { LOG.debug("Error reading input", e); throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, e); } - final var rpcName = context.getSchemaNode().getQName(); - final ListenableFuture future; - final var mountPoint = context.getMountPoint(); - if (mountPoint == null) { - if (CreateDataChangeEventSubscription.QNAME.equals(rpcName)) { - future = Futures.immediateFuture(CreateStreamUtil.createDataChangeNotifiStream( - streamUtils.listenersBroker(), input, schemaContext)); - } else if (SubscribeDeviceNotification.QNAME.equals(rpcName)) { - final String baseUrl = streamUtils.prepareUriByStreamName(uriInfo, "").toString(); - future = Futures.immediateFuture(CreateStreamUtil.createDeviceNotificationListener(baseUrl, input, - streamUtils, mountPointService)); - } else { - future = invokeRpc(input, rpcName, rpcService); - } - } else { - future = invokeRpc(input, rpcName, mountPoint); - } - - Futures.addCallback(future, new FutureCallback() { + Futures.addCallback(hackInvokeRpc(databind, reqPath, uriInfo, input), new FutureCallback<>() { @Override - public void onSuccess(final DOMRpcResult response) { - final var errors = response.errors(); - if (!errors.isEmpty()) { - LOG.debug("RpcError message {}", response.errors()); - ar.resume(new RestconfDocumentedException("RPCerror message ", null, response.errors())); - return; - } - - final ContainerNode resultData = response.value(); - if (resultData == null || resultData.isEmpty()) { - ar.resume(Response.noContent().build()); - } else { - ar.resume(Response.ok().entity(new NormalizedNodePayload(context.inference(), resultData)).build()); + public void onSuccess(final Optional result) { + if (result.isPresent()) { + final var output = result.orElseThrow(); + if (!output.isEmpty()) { + ar.resume(Response.ok().entity(new NormalizedNodePayload(reqPath.inference(), output)).build()); + return; + } } + ar.resume(Response.noContent().build()); } @Override @@ -196,43 +164,23 @@ public final class RestconfInvokeOperationsServiceImpl { }, MoreExecutors.directExecutor()); } - /** - * Invoking rpc via mount point. - * - * @param mountPoint mount point - * @param data input data - * @param rpc RPC type - * @return {@link DOMRpcResult} - */ - @VisibleForTesting - static ListenableFuture invokeRpc(final ContainerNode data, final QName rpc, - final DOMMountPoint mountPoint) { - return invokeRpc(data, rpc, mountPoint.getService(DOMRpcService.class).orElseThrow(() -> { - final String errmsg = "RPC service is missing."; - LOG.debug(errmsg); - return new RestconfDocumentedException(errmsg); - })); - } - - /** - * Invoke rpc. - * - * @param input input data - * @param rpc RPC type - * @param rpcService rpc service to invoke rpc - * @return {@link DOMRpcResult} - */ - @VisibleForTesting - static ListenableFuture invokeRpc(final ContainerNode input, final QName rpc, - final DOMRpcService rpcService) { - return Futures.catching(rpcService.invokeRpc(rpc, nonnullInput(rpc, input)), DOMRpcException.class, - cause -> new DefaultDOMRpcResult(List.of(RpcResultBuilder.newError(ErrorType.RPC, ErrorTag.OPERATION_FAILED, - cause.getMessage()))), - MoreExecutors.directExecutor()); - } + private RestconfFuture> hackInvokeRpc(final DatabindContext localDatabind, + final InstanceIdentifierContext reqPath, final UriInfo uriInfo, final ContainerNode input) { + // RPC type + final var type = reqPath.getSchemaNode().getQName(); + final var mountPoint = reqPath.getMountPoint(); + if (mountPoint == null) { + // Hacked-up integration of streams + if (CreateDataChangeEventSubscription.QNAME.equals(type)) { + return RestconfFuture.of(Optional.of(CreateStreamUtil.createDataChangeNotifiStream( + streamUtils.listenersBroker(), input, localDatabind.modelContext()))); + } else if (SubscribeDeviceNotification.QNAME.equals(type)) { + final var baseUrl = streamUtils.prepareUriByStreamName(uriInfo, "").toString(); + return RestconfFuture.of(Optional.of(CreateStreamUtil.createDeviceNotificationListener(baseUrl, input, + streamUtils, mountPointService))); + } + } - private static @NonNull ContainerNode nonnullInput(final QName type, final ContainerNode input) { - return input != null ? input - : ImmutableNodes.containerNode(YangConstants.operationInputQName(type.getModule())); + return server.getRestconfStrategy(reqPath.getSchemaContext(), mountPoint).invokeRpc(type, input); } } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java index 84e2c78b9d..7368688f14 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java @@ -14,10 +14,8 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; -import org.opendaylight.mdsal.dom.api.DOMMountPointService; import org.opendaylight.restconf.nb.rfc8040.MediaTypes; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider; -import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; /** @@ -26,18 +24,17 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; @Path("/") public final class RestconfOperationsServiceImpl { private final DatabindProvider databindProvider; - private final DOMMountPointService mountPointService; + private final MdsalRestconfServer server; /** * Set {@link DatabindProvider} for getting actual {@link EffectiveModelContext}. * * @param databindProvider a {@link DatabindProvider} - * @param mountPointService a {@link DOMMountPointService} + * @param server a {@link MdsalRestconfServer} */ - public RestconfOperationsServiceImpl(final DatabindProvider databindProvider, - final DOMMountPointService mountPointService) { + public RestconfOperationsServiceImpl(final DatabindProvider databindProvider, final MdsalRestconfServer server) { this.databindProvider = requireNonNull(databindProvider); - this.mountPointService = requireNonNull(mountPointService); + this.server = requireNonNull(server); } /** @@ -49,7 +46,8 @@ public final class RestconfOperationsServiceImpl { @Path("/operations") @Produces({ MediaTypes.APPLICATION_YANG_DATA_JSON, MediaType.APPLICATION_JSON }) public String getOperationsJSON() { - return OperationsContent.JSON.bodyFor(databindProvider.currentContext().modelContext()); + return OperationsContent.JSON.bodyFor( + server.bindRequestRoot(databindProvider.currentContext()).inference()); } /** @@ -62,8 +60,8 @@ public final class RestconfOperationsServiceImpl { @Path("/operations/{identifier:.+}") @Produces({ MediaTypes.APPLICATION_YANG_DATA_JSON, MediaType.APPLICATION_JSON }) public String getOperationJSON(@PathParam("identifier") final String identifier) { - return OperationsContent.JSON.bodyFor(ParserIdentifier.toInstanceIdentifier(identifier, - databindProvider.currentContext().modelContext(), mountPointService).inference()); + return OperationsContent.JSON.bodyFor( + server.bindRequestPath(databindProvider.currentContext(), identifier).inference()); } /** @@ -75,7 +73,8 @@ public final class RestconfOperationsServiceImpl { @Path("/operations") @Produces({ MediaTypes.APPLICATION_YANG_DATA_XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public String getOperationsXML() { - return OperationsContent.XML.bodyFor(databindProvider.currentContext().modelContext()); + return OperationsContent.XML.bodyFor( + server.bindRequestRoot(databindProvider.currentContext()).inference()); } /** @@ -88,7 +87,7 @@ public final class RestconfOperationsServiceImpl { @Path("/operations/{identifier:.+}") @Produces({ MediaTypes.APPLICATION_YANG_DATA_XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public String getOperationXML(@PathParam("identifier") final String identifier) { - return OperationsContent.XML.bodyFor(ParserIdentifier.toInstanceIdentifier(identifier, - databindProvider.currentContext().modelContext(), mountPointService).inference()); + return OperationsContent.XML.bodyFor( + server.bindRequestPath(databindProvider.currentContext(), identifier).inference()); } } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategy.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategy.java index 30aca2def9..5400c52b36 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategy.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategy.java @@ -16,10 +16,12 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.List; import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMTransactionChain; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.common.errors.SettableRestconfFuture; @@ -39,8 +41,9 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; public final class MdsalRestconfStrategy extends RestconfStrategy { private final DOMDataBroker dataBroker; - public MdsalRestconfStrategy(final EffectiveModelContext modelContext, final DOMDataBroker dataBroker) { - super(modelContext); + public MdsalRestconfStrategy(final EffectiveModelContext modelContext, final DOMDataBroker dataBroker, + final @Nullable DOMRpcService rpcService) { + super(modelContext, rpcService); this.dataBroker = requireNonNull(dataBroker); } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategy.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategy.java index 60fd463c04..a3f567ed20 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategy.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategy.java @@ -16,9 +16,11 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.util.List; import java.util.Optional; +import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.common.api.ReadFailedException; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.netconf.dom.api.NetconfDataTreeService; import org.opendaylight.restconf.common.errors.SettableRestconfFuture; import org.opendaylight.yangtools.yang.common.Empty; @@ -35,8 +37,8 @@ public final class NetconfRestconfStrategy extends RestconfStrategy { private final NetconfDataTreeService netconfService; public NetconfRestconfStrategy(final EffectiveModelContext modelContext, - final NetconfDataTreeService netconfService) { - super(modelContext); + final NetconfDataTreeService netconfService, final @Nullable DOMRpcService rpcService) { + super(modelContext, rpcService); this.netconfService = requireNonNull(netconfService); } diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/RestconfStrategy.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/RestconfStrategy.java index 1b33afda3a..90d0d37290 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/RestconfStrategy.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/RestconfStrategy.java @@ -28,6 +28,8 @@ import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMRpcResult; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMTransactionChain; import org.opendaylight.netconf.dom.api.NetconfDataTreeService; import org.opendaylight.restconf.api.query.ContentParam; @@ -109,9 +111,11 @@ public abstract class RestconfStrategy { private static final Logger LOG = LoggerFactory.getLogger(RestconfStrategy.class); private final @NonNull EffectiveModelContext modelContext; + private final @Nullable DOMRpcService rpcService; - RestconfStrategy(final EffectiveModelContext modelContext) { + RestconfStrategy(final EffectiveModelContext modelContext, final @Nullable DOMRpcService rpcService) { this.modelContext = requireNonNull(modelContext); + this.rpcService = rpcService; } /** @@ -124,13 +128,15 @@ public abstract class RestconfStrategy { */ public static @Nullable RestconfStrategy forMountPoint(final EffectiveModelContext modelContext, final DOMMountPoint mountPoint) { + final var rpcService = mountPoint.getService(DOMRpcService.class).orElse(null); + final var netconfService = mountPoint.getService(NetconfDataTreeService.class); if (netconfService.isPresent()) { - return new NetconfRestconfStrategy(modelContext, netconfService.orElseThrow()); + return new NetconfRestconfStrategy(modelContext, netconfService.orElseThrow(), rpcService); } final var dataBroker = mountPoint.getService(DOMDataBroker.class); if (dataBroker.isPresent()) { - return new MdsalRestconfStrategy(modelContext, dataBroker.orElseThrow()); + return new MdsalRestconfStrategy(modelContext, dataBroker.orElseThrow(), rpcService); } return null; } @@ -995,4 +1001,43 @@ public abstract class RestconfStrategy { configMap.entrySet().stream().filter(x -> stateMap.containsKey(x.getKey())).forEach( y -> builder.addChild((T) prepareData(y.getValue(), stateMap.get(y.getKey())))); } + + public @NonNull RestconfFuture> invokeRpc(final QName type, final ContainerNode input) { + final var ret = new SettableRestconfFuture>(); + + final var local = rpcService; + if (local != null) { + Futures.addCallback(local.invokeRpc(requireNonNull(type), requireNonNull(input)), + new FutureCallback() { + @Override + public void onSuccess(final DOMRpcResult response) { + final var errors = response.errors(); + if (errors.isEmpty()) { + ret.set(Optional.ofNullable(response.value())); + } else { + LOG.debug("RPC invocation reported {}", response.errors()); + ret.setFailure(new RestconfDocumentedException("RPC implementation reported errors", null, + response.errors())); + } + } + + @Override + public void onFailure(final Throwable cause) { + LOG.debug("RPC invocation failed, cause"); + if (cause instanceof RestconfDocumentedException ex) { + ret.setFailure(ex); + } else { + // TODO: YangNetconfErrorAware if we ever get into a broader invocation scope + ret.setFailure(new RestconfDocumentedException(cause, + new RestconfError(ErrorType.RPC, ErrorTag.OPERATION_FAILED, cause.getMessage()))); + } + } + }, MoreExecutors.directExecutor()); + } else { + LOG.debug("RPC invocation is not available"); + ret.setFailure(new RestconfDocumentedException("RPC invocation is not available", + ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED)); + } + return ret; + } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtilTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtilTest.java index 153af880c9..804e0149d9 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtilTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtilTest.java @@ -13,13 +13,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; -import java.util.List; import java.util.function.Function; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; -import org.opendaylight.mdsal.dom.api.DOMRpcResult; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker; import org.opendaylight.yangtools.yang.common.ErrorTag; @@ -51,14 +49,12 @@ public class CreateStreamUtilTest { @Test public void createStreamTest() { - final DOMRpcResult result = CreateStreamUtil.createDataChangeNotifiStream(listenersBroker, - prepareDomPayload("create-data-change-event-subscription", RpcDefinition::getInput, "toaster", "path"), - SCHEMA_CTX); - assertEquals(List.of(), result.errors()); assertEquals(prepareDomPayload("create-data-change-event-subscription", RpcDefinition::getOutput, "data-change-event-subscription/toaster:toaster/datastore=CONFIGURATION/scope=BASE", "stream-name"), - result.value()); + CreateStreamUtil.createDataChangeNotifiStream(listenersBroker, + prepareDomPayload("create-data-change-event-subscription", RpcDefinition::getInput, "toaster", "path"), + SCHEMA_CTX)); } @Test diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServerTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServerTest.java new file mode 100644 index 0000000000..1b3f633bf6 --- /dev/null +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServerTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 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.rests.services.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doReturn; + +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; +import org.opendaylight.mdsal.dom.api.DOMMountPoint; +import org.opendaylight.mdsal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMRpcService; +import org.opendaylight.netconf.dom.api.NetconfDataTreeService; +import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest; +import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy; +import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy; +import org.opendaylight.yangtools.yang.common.ErrorTag; +import org.opendaylight.yangtools.yang.common.ErrorType; + +@RunWith(MockitoJUnitRunner.StrictStubs.class) +public class MdsalRestconfServerTest extends AbstractJukeboxTest { + @Mock + private DOMMountPointService mountPointService; + @Mock + private DOMMountPoint mountPoint; + @Mock + private DOMDataBroker dataBroker; + @Mock + private NetconfDataTreeService netconfService; + @Mock + private DOMRpcService rpcService; + + private MdsalRestconfServer server; + + @Before + public void before() { + server = new MdsalRestconfServer(dataBroker, rpcService, mountPointService); + doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class); + } + + @Test + public void testGetRestconfStrategyLocal() { + assertInstanceOf(MdsalRestconfStrategy.class, server.getRestconfStrategy(JUKEBOX_SCHEMA, null)); + } + + @Test + public void testGetRestconfStrategyMountDataBroker() { + doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class); + doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class); + assertInstanceOf(MdsalRestconfStrategy.class, server.getRestconfStrategy(JUKEBOX_SCHEMA, mountPoint)); + } + + @Test + public void testGetRestconfStrategyMountNetconfService() { + doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class); + assertInstanceOf(NetconfRestconfStrategy.class, server.getRestconfStrategy(JUKEBOX_SCHEMA, mountPoint)); + } + + @Test + public void testGetRestconfStrategyMountNone() { + doReturn(JUKEBOX_IID).when(mountPoint).getIdentifier(); + doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class); + doReturn(Optional.empty()).when(mountPoint).getService(DOMDataBroker.class); + final var ex = assertThrows(RestconfDocumentedException.class, + () -> server.getRestconfStrategy(JUKEBOX_SCHEMA, mountPoint)); + final var errors = ex.getErrors(); + assertEquals(1, errors.size()); + final var error = errors.get(0); + assertEquals(ErrorType.APPLICATION, error.getErrorType()); + assertEquals(ErrorTag.OPERATION_FAILED, error.getErrorTag()); + assertEquals("Could not find a supported access interface in mount point " + + "/(http://example.com/ns/example-jukebox?revision=2015-04-04)jukebox", error.getErrorMessage()); + // FIXME: should be JUKEBOX_IID + assertNull(error.getErrorPath()); + } +} diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf799Test.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf799Test.java index 452614e4c5..8c0c252b5f 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf799Test.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf799Test.java @@ -21,6 +21,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.mdsal.dom.api.DOMActionService; import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.spi.SimpleDOMActionResult; import org.opendaylight.restconf.nb.rfc8040.AbstractInstanceIdentifierTest; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; @@ -40,6 +41,8 @@ public class Netconf799Test extends AbstractInstanceIdentifierTest { @Mock private DOMActionService actionService; @Mock + private DOMRpcService rpcService; + @Mock private DOMMountPointService mountPointService; @Mock private RestconfStreamsSubscriptionService restconfStreamSubService; @@ -50,8 +53,8 @@ public class Netconf799Test extends AbstractInstanceIdentifierTest { Builders.containerBuilder().withNodeIdentifier(NodeIdentifier.create(OUTPUT_QNAME)).build()))) .when(actionService).invokeAction(eq(Absolute.of(CONT_QNAME, CONT1_QNAME, RESET_QNAME)), any(), any()); - final var dataService = new RestconfDataServiceImpl( - () -> DatabindContext.ofModel(IID_SCHEMA), dataBroker, mountPointService, restconfStreamSubService, + final var dataService = new RestconfDataServiceImpl(() -> DatabindContext.ofModel(IID_SCHEMA), + new MdsalRestconfServer(dataBroker, rpcService, mountPointService), dataBroker, restconfStreamSubService, actionService, new StreamsConfiguration(0, 1, 0, false)); final var response = dataService.postDataJSON("instance-identifier-module:cont/cont1/reset", diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java index a7cccb1e10..7c8c9bbf45 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java @@ -12,20 +12,19 @@ import static org.junit.Assert.assertEquals; import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.Revision; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; -import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; public class Netconf822Test { - private static Inference INFERENCE; + private static final Absolute NEW1 = Absolute.of(QName.create("foo", "2021-09-30", "new1")); + + private static EffectiveModelContext SCHEMA; @BeforeClass public static void beforeClass() { - final var context = YangParserTestUtils.parseYangResourceDirectory("/nc822"); - INFERENCE = SchemaInferenceStack.of(context, - Absolute.of(QName.create("foo", "new1", Revision.of("2021-09-30")))).toInference(); + SCHEMA = YangParserTestUtils.parseYangResourceDirectory("/nc822"); } @Test @@ -36,7 +35,7 @@ public class Netconf822Test { "foo:new": [null], "foo:new1": [null] } - }""", OperationsContent.JSON.bodyFor(INFERENCE.getEffectiveModelContext())); + }""", OperationsContent.JSON.bodyFor(SchemaInferenceStack.of(SCHEMA).toInference())); } @Test @@ -46,7 +45,7 @@ public class Netconf822Test { "ietf-restconf:operations" : { "foo:new1": [null] } - }""", OperationsContent.JSON.bodyFor(INFERENCE)); + }""", OperationsContent.JSON.bodyFor(SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); } @Test @@ -57,7 +56,7 @@ public class Netconf822Test { xmlns:ns0="foo" > - """, OperationsContent.XML.bodyFor(INFERENCE.getEffectiveModelContext())); + """, OperationsContent.XML.bodyFor(SchemaInferenceStack.of(SCHEMA).toInference())); } @Test @@ -67,6 +66,6 @@ public class Netconf822Test { - """, OperationsContent.XML.bodyFor(INFERENCE)); + """, OperationsContent.XML.bodyFor(SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImplTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImplTest.java index e4e83a1cdb..fdd2883110 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImplTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfDataServiceImplTest.java @@ -49,6 +49,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; import org.opendaylight.mdsal.dom.api.DOMMountPoint; import org.opendaylight.mdsal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService; import org.opendaylight.netconf.dom.api.NetconfDataTreeService; @@ -60,8 +61,6 @@ import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; import org.opendaylight.restconf.nb.rfc8040.rests.services.api.RestconfStreamsSubscriptionService; -import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy; -import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy; import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.yang.patch.Edit.Operation; import org.opendaylight.yangtools.yang.common.ErrorTag; @@ -111,6 +110,8 @@ public class RestconfDataServiceImplTest extends AbstractJukeboxTest { @Mock private DOMActionService actionService; @Mock + private DOMRpcService rpcService; + @Mock private RestconfStreamsSubscriptionService delegRestconfSubscrService; @Mock private MultivaluedMap queryParamenters; @@ -128,13 +129,15 @@ public class RestconfDataServiceImplTest extends AbstractJukeboxTest { doReturn(read).when(dataBroker).newReadOnlyTransaction(); doReturn(readWrite).when(dataBroker).newReadWriteTransaction(); - dataService = new RestconfDataServiceImpl(() -> DatabindContext.ofModel(JUKEBOX_SCHEMA), dataBroker, - mountPointService, delegRestconfSubscrService, actionService, new StreamsConfiguration(0, 1, 0, false)); + dataService = new RestconfDataServiceImpl(() -> DatabindContext.ofModel(JUKEBOX_SCHEMA), + new MdsalRestconfServer(dataBroker, rpcService, mountPointService), dataBroker, delegRestconfSubscrService, + actionService, new StreamsConfiguration(0, 1, 0, false)); doReturn(Optional.of(mountPoint)).when(mountPointService) .getMountPoint(any(YangInstanceIdentifier.class)); doReturn(Optional.of(FixedDOMSchemaService.of(JUKEBOX_SCHEMA))).when(mountPoint) .getService(DOMSchemaService.class); doReturn(Optional.of(mountDataBroker)).when(mountPoint).getService(DOMDataBroker.class); + doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class); doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class); doReturn(read).when(mountDataBroker).newReadOnlyTransaction(); doReturn(readWrite).when(mountDataBroker).newReadWriteTransaction(); @@ -460,14 +463,4 @@ public class RestconfDataServiceImplTest extends AbstractJukeboxTest { final String errorMessage = status.editCollection().get(2).getEditErrors().get(0).getErrorMessage(); assertEquals("Data does not exist", errorMessage); } - - @Test - public void testGetRestconfStrategy() { - var restconfStrategy = dataService.getRestconfStrategy(JUKEBOX_SCHEMA, mountPoint); - assertTrue(restconfStrategy instanceof MdsalRestconfStrategy); - - doReturn(Optional.of(netconfService)).when(mountPoint).getService(NetconfDataTreeService.class); - restconfStrategy = dataService.getRestconfStrategy(JUKEBOX_SCHEMA, mountPoint); - assertTrue(restconfStrategy instanceof NetconfRestconfStrategy); - } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java index ea8b545a53..ba9af579fa 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java @@ -7,22 +7,19 @@ */ package org.opendaylight.restconf.nb.rfc8040.rests.services.impl; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; -import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture; -import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture; +import com.google.common.util.concurrent.Futures; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutionException; @@ -36,13 +33,14 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMMountPoint; import org.opendaylight.mdsal.dom.api.DOMMountPointService; -import org.opendaylight.mdsal.dom.api.DOMRpcException; import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException; import org.opendaylight.mdsal.dom.api.DOMRpcResult; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult; +import org.opendaylight.netconf.dom.api.NetconfDataTreeService; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; @@ -50,7 +48,6 @@ import org.opendaylight.restconf.nb.rfc8040.streams.StreamsConfiguration; import org.opendaylight.yangtools.yang.common.ErrorTag; import org.opendaylight.yangtools.yang.common.ErrorType; import org.opendaylight.yangtools.yang.common.QName; -import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; @@ -71,13 +68,17 @@ public class RestconfInvokeOperationsServiceImplTest { private static DatabindContext CONTEXT; + @Mock + private DOMDataBroker dataBroker; @Mock private DOMRpcService rpcService; @Mock private DOMMountPoint mountPoint; @Mock private DOMMountPointService mountPointService; + private RestconfInvokeOperationsServiceImpl invokeOperationsService; + private MdsalRestconfServer server; @BeforeClass public static void beforeClass() { @@ -86,7 +87,8 @@ public class RestconfInvokeOperationsServiceImplTest { @Before public void setup() { - invokeOperationsService = new RestconfInvokeOperationsServiceImpl(() -> CONTEXT, rpcService, mountPointService, + server = new MdsalRestconfServer(dataBroker, rpcService, mountPointService); + invokeOperationsService = new RestconfInvokeOperationsServiceImpl(() -> CONTEXT, server, mountPointService, new StreamsConfiguration(0, 1, 0, false)); } @@ -116,74 +118,82 @@ public class RestconfInvokeOperationsServiceImplTest { prepNNC(result); final var ar = mock(AsyncResponse.class); - final var captor = ArgumentCaptor.forClass(Response.class); + final var response = ArgumentCaptor.forClass(Response.class); invokeOperationsService.invokeRpcJSON("invoke-rpc-module:rpc-test", new ByteArrayInputStream(""" { "invoke-rpc-module:input" : { } } """.getBytes(StandardCharsets.UTF_8)), mock(UriInfo.class), ar); - verify(ar).resume(captor.capture()); + verify(ar).resume(response.capture()); - final var response = captor.getValue(); - assertEquals(204, response.getStatus()); + assertEquals(204, response.getValue().getStatus()); } @Test - public void invokeRpcTest() throws InterruptedException, ExecutionException { - final DOMRpcResult mockResult = new DefaultDOMRpcResult(OUTPUT, List.of()); - doReturn(immediateFluentFuture(mockResult)).when(rpcService).invokeRpc(RPC, INPUT); - final DOMRpcResult rpcResult = RestconfInvokeOperationsServiceImpl.invokeRpc(INPUT, RPC, rpcService).get(); - assertTrue(rpcResult.errors().isEmpty()); - assertEquals(OUTPUT, rpcResult.value()); + public void invokeRpcTest() throws Exception { + doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))).when(rpcService) + .invokeRpc(RPC, INPUT); + assertEquals(Optional.of(OUTPUT), Futures.getDone(server.getRestconfStrategy(CONTEXT.modelContext(), null) + .invokeRpc(RPC, INPUT))); } @Test - public void invokeRpcErrorsAndCheckTestTest() throws InterruptedException, ExecutionException { - final QName errorRpc = QName.create(RPC, "error-rpc"); - final DOMRpcException exception = new DOMRpcImplementationNotAvailableException( + public void invokeRpcErrorsAndCheckTestTest() throws Exception { + final var errorRpc = QName.create(RPC, "error-rpc"); + final var exception = new DOMRpcImplementationNotAvailableException( "No implementation of RPC " + errorRpc + " available."); - doReturn(immediateFailedFluentFuture(exception)).when(rpcService).invokeRpc(errorRpc, INPUT); - final DOMRpcResult rpcResult = RestconfInvokeOperationsServiceImpl.invokeRpc(INPUT, errorRpc, rpcService).get(); - assertNull(rpcResult.value()); - final Collection errorList = rpcResult.errors(); + doReturn(Futures.immediateFailedFuture(exception)).when(rpcService).invokeRpc(errorRpc, INPUT); + final var ex = assertInstanceOf(RestconfDocumentedException.class, + assertThrows(ExecutionException.class, () -> Futures.getDone( + server.getRestconfStrategy(CONTEXT.modelContext(), null).invokeRpc(errorRpc, INPUT))).getCause()); + final var errorList = ex.getErrors(); assertEquals(1, errorList.size()); - final RpcError actual = errorList.iterator().next(); - assertEquals("No implementation of RPC " + errorRpc + " available.", actual.getMessage()); - assertEquals(ErrorTag.OPERATION_FAILED, actual.getTag()); + final var actual = errorList.iterator().next(); + assertEquals("No implementation of RPC " + errorRpc + " available.", actual.getErrorMessage()); assertEquals(ErrorType.RPC, actual.getErrorType()); + assertEquals(ErrorTag.OPERATION_FAILED, actual.getErrorTag()); } @Test - public void invokeRpcViaMountPointTest() throws InterruptedException, ExecutionException { - doReturn(Optional.ofNullable(rpcService)).when(mountPoint).getService(DOMRpcService.class); - final DOMRpcResult mockResult = new DefaultDOMRpcResult(OUTPUT, List.of()); - doReturn(immediateFluentFuture(mockResult)).when(rpcService).invokeRpc(RPC, INPUT); - final DOMRpcResult rpcResult = RestconfInvokeOperationsServiceImpl.invokeRpc(INPUT, RPC, mountPoint).get(); - assertTrue(rpcResult.errors().isEmpty()); - assertEquals(OUTPUT, rpcResult.value()); + public void invokeRpcViaMountPointTest() throws Exception { + doReturn(Optional.of(rpcService)).when(mountPoint).getService(DOMRpcService.class); + doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class); + doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class); + doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))).when(rpcService) + .invokeRpc(RPC, INPUT); + assertEquals(Optional.of(OUTPUT), Futures.getDone( + server.getRestconfStrategy(CONTEXT.modelContext(), mountPoint).invokeRpc(RPC, INPUT))); } @Test public void invokeRpcMissingMountPointServiceTest() { doReturn(Optional.empty()).when(mountPoint).getService(DOMRpcService.class); - assertThrows(RestconfDocumentedException.class, - () -> RestconfInvokeOperationsServiceImpl.invokeRpc(INPUT, RPC, mountPoint)); + doReturn(Optional.empty()).when(mountPoint).getService(NetconfDataTreeService.class); + doReturn(Optional.of(dataBroker)).when(mountPoint).getService(DOMDataBroker.class); + final var strategy = server.getRestconfStrategy(CONTEXT.modelContext(), mountPoint); + final var ex = assertInstanceOf(RestconfDocumentedException.class, + assertThrows(ExecutionException.class, () -> Futures.getDone(strategy.invokeRpc(RPC, INPUT))).getCause()); + final var errors = ex.getErrors(); + assertEquals(1, errors.size()); + final var error = errors.get(0); + assertEquals(ErrorType.PROTOCOL, error.getErrorType()); + assertEquals(ErrorTag.OPERATION_NOT_SUPPORTED, error.getErrorTag()); + assertEquals("RPC invocation is not available", error.getErrorMessage()); } @Test - public void checkResponseTest() throws InterruptedException, ExecutionException { - doReturn(immediateFluentFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))) + public void checkResponseTest() throws Exception { + doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(OUTPUT, List.of()))) .when(rpcService).invokeRpc(RPC, INPUT); - final DOMRpcResult rpcResult = RestconfInvokeOperationsServiceImpl.invokeRpc(INPUT, RPC, rpcService).get(); - assertTrue(rpcResult.errors().isEmpty()); - assertEquals(OUTPUT, rpcResult.value()); + assertEquals(Optional.of(OUTPUT), Futures.getDone( + server.getRestconfStrategy(CONTEXT.modelContext(), null).invokeRpc(RPC, INPUT))); } private void prepNNC(final ContainerNode result) { - final QName qname = QName.create("invoke:rpc:module", "2013-12-03", "rpc-test"); - final DOMRpcResult domRpcResult = mock(DOMRpcResult.class); - doReturn(immediateFluentFuture(domRpcResult)).when(rpcService).invokeRpc(eq(qname), any(ContainerNode.class)); + final var qname = QName.create("invoke:rpc:module", "2013-12-03", "rpc-test"); + final var domRpcResult = mock(DOMRpcResult.class); + doReturn(Futures.immediateFuture(domRpcResult)).when(rpcService).invokeRpc(eq(qname), any(ContainerNode.class)); doReturn(result).when(domRpcResult).value(); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java index 4ed44d9396..79768ec77e 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java @@ -19,8 +19,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.mdsal.binding.runtime.spi.BindingRuntimeHelpers; +import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMMountPoint; import org.opendaylight.mdsal.dom.api.DOMMountPointService; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; import org.opendaylight.yang.gen.v1.module._1.rev140101.Module1Data; @@ -61,6 +63,10 @@ public class RestconfOperationsServiceImplTest { private DOMMountPoint mountPoint; @Mock private DOMSchemaService schemaService; + @Mock + private DOMDataBroker dataBroker; + @Mock + private DOMRpcService rpcService; private RestconfOperationsServiceImpl opService; @@ -75,7 +81,9 @@ public class RestconfOperationsServiceImplTest { doReturn(SCHEMA).when(schemaService).getGlobalContext(); doReturn(Optional.of(schemaService)).when(mountPoint).getService(DOMSchemaService.class); doReturn(Optional.of(mountPoint)).when(mountPointService).getMountPoint(any()); - opService = new RestconfOperationsServiceImpl(() -> DatabindContext.ofModel(SCHEMA), mountPointService); + + opService = new RestconfOperationsServiceImpl(() -> DatabindContext.ofModel(SCHEMA), + new MdsalRestconfServer(dataBroker, rpcService, mountPointService)); } @Test diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategyTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategyTest.java index 945f2ff670..f5a7fd786f 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategyTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/MdsalRestconfStrategyTest.java @@ -30,6 +30,7 @@ import org.opendaylight.mdsal.common.api.LogicalDatastoreType; import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; +import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.restconf.api.query.ContentParam; import org.opendaylight.restconf.api.query.WithDefaultsParam; import org.opendaylight.restconf.common.patch.PatchStatusContext; @@ -55,6 +56,8 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes private DOMDataBroker mockDataBroker; @Mock private DOMDataTreeReadTransaction read; + @Mock + private DOMRpcService rpcService; @BeforeClass public static void setupModulesSchema() { @@ -77,7 +80,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes // assert that data to delete exists when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of())) .thenReturn(immediateTrueFluentFuture()); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override @@ -85,7 +88,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes // assert that data to delete does NOT exist when(readWrite.exists(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of())) .thenReturn(immediateFalseFluentFuture()); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override @@ -93,7 +96,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, node); doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, node, entryNode); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override @@ -101,7 +104,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID); doReturn(immediateFailedFluentFuture(domException)).when(readWrite).commit(); doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Test @@ -112,7 +115,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); + new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID); verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX); } @@ -125,7 +128,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(GAP_IID, GAP_LEAF, null); + new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null).putData(GAP_IID, GAP_LEAF, null); verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID); verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF); } @@ -140,7 +143,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); + new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID); verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS); } @@ -150,33 +153,33 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID); doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy testPatchContainerDataStrategy() { doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction(); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy testPatchLeafDataStrategy() { doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction(); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy testPatchListDataStrategy() { doReturn(readWrite).when(mockDataBroker).newReadWriteTransaction(); doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit(); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy testPatchDataReplaceMergeAndRemoveStrategy() { - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override @@ -184,19 +187,19 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, PLAYER_IID); doReturn(immediateTrueFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy testPatchMergePutContainerStrategy() { - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override RestconfStrategy deleteNonexistentDataTestStrategy() { doReturn(immediateFalseFluentFuture()).when(readWrite).exists(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET); - return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker); + return new MdsalRestconfStrategy(JUKEBOX_SCHEMA, mockDataBroker, null); } @Override @@ -215,7 +218,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(read).when(mockDataBroker).newReadOnlyTransaction(); doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(read) .read(LogicalDatastoreType.CONFIGURATION, PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -225,7 +228,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.CONFIGURATION, PATH); doReturn(immediateFluentFuture(Optional.empty())).when(read) .read(LogicalDatastoreType.OPERATIONAL, PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -235,7 +238,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, PATH_2); doReturn(immediateFluentFuture(Optional.empty())).when(read) .read(LogicalDatastoreType.CONFIGURATION, PATH_2); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -243,7 +246,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(read).when(mockDataBroker).newReadOnlyTransaction(); doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(read) .read(LogicalDatastoreType.OPERATIONAL, PATH_2); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -253,7 +256,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.CONFIGURATION, PATH); doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read) .read(LogicalDatastoreType.OPERATIONAL, PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -263,7 +266,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.CONFIGURATION, PATH); doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(read) .read(LogicalDatastoreType.OPERATIONAL, PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -273,7 +276,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, PATH_3); doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(read) .read(LogicalDatastoreType.CONFIGURATION, PATH_3); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -283,7 +286,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, PATH_3); doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(read) .read(LogicalDatastoreType.CONFIGURATION, PATH_3); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -293,7 +296,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, PATH_3); doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(read) .read(LogicalDatastoreType.CONFIGURATION, PATH_3); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -303,7 +306,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH); doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(read) .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override @@ -313,14 +316,14 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes .read(LogicalDatastoreType.OPERATIONAL, LEAF_SET_NODE_PATH); doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(read) .read(LogicalDatastoreType.CONFIGURATION, LEAF_SET_NODE_PATH); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Override RestconfStrategy readDataWrongPathOrNoContentTestStrategy() { doReturn(read).when(mockDataBroker).newReadOnlyTransaction(); doReturn(immediateFluentFuture(Optional.empty())).when(read).read(LogicalDatastoreType.CONFIGURATION, PATH_2); - return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker); + return new MdsalRestconfStrategy(mockSchemaContext, mockDataBroker, null); } @Test @@ -336,8 +339,8 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFluentFuture(Optional.of(data))).when(read) .read(LogicalDatastoreType.OPERATIONAL, path); - assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path, - WithDefaultsParam.TRIM)); + assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker, null) + .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM)); } @Test @@ -367,8 +370,8 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFluentFuture(Optional.of(data))).when(read) .read(LogicalDatastoreType.OPERATIONAL, path); - assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path, - WithDefaultsParam.TRIM)); + assertEquals(data, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker, null) + .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM)); } @Test @@ -391,7 +394,7 @@ public final class MdsalRestconfStrategyTest extends AbstractRestconfStrategyTes doReturn(immediateFluentFuture(Optional.of(content))).when(read) .read(LogicalDatastoreType.OPERATIONAL, path); - assertEquals(content, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker).readData(ContentParam.ALL, path, - WithDefaultsParam.TRIM)); + assertEquals(content, new MdsalRestconfStrategy(MODULES_SCHEMA, mockDataBroker, null) + .readData(ContentParam.ALL, path, WithDefaultsParam.TRIM)); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategyTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategyTest.java index 380273e635..b9c6494a55 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategyTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/transactions/NetconfRestconfStrategyTest.java @@ -55,7 +55,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT @Override RestconfStrategy testDeleteDataStrategy() { - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -63,7 +63,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFailedFuture(new TransactionCommitFailedException( "Commit of transaction " + this + " failed", new NetconfDocumentedException("id", ErrorType.RPC, ErrorTag.DATA_MISSING, ErrorSeverity.ERROR)))).when(netconfService).commit(); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -71,7 +71,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit(); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .create(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty()); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -82,7 +82,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit(); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).create( LogicalDatastoreType.CONFIGURATION, node, entryNode, Optional.empty()); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -92,14 +92,14 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT .create(any(), any(), any(), any()); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).discardChanges(); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).unlock(); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override RestconfStrategy testPatchContainerDataStrategy() { doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).merge(any(), any(),any(), any()); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -107,7 +107,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .merge(any(), any(), any(), any()); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit(); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -115,7 +115,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService).commit(); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .merge(any(), any(),any(),any()); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Test @@ -125,7 +125,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); verify(netconfService).lock(); verify(netconfService).getConfig(JUKEBOX_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, @@ -140,7 +140,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null).putData(JUKEBOX_IID, EMPTY_JUKEBOX, null); verify(netconfService).getConfig(JUKEBOX_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty()); @@ -153,7 +153,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(GAP_IID, GAP_LEAF, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null).putData(GAP_IID, GAP_LEAF, null); verify(netconfService).getConfig(GAP_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty()); } @@ -166,7 +166,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(GAP_IID, GAP_LEAF, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null).putData(GAP_IID, GAP_LEAF, null); verify(netconfService).getConfig(GAP_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty()); } @@ -178,7 +178,8 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null) + .putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); verify(netconfService).getConfig(JUKEBOX_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty()); @@ -192,7 +193,8 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty()); - new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); + new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null) + .putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, null); verify(netconfService).getConfig(JUKEBOX_IID); verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty()); @@ -205,7 +207,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) // FIXME: exact match .replace(any(), any(), any(), any()); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -214,12 +216,12 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT .create(LogicalDatastoreType.CONFIGURATION, PLAYER_IID, EMPTY_JUKEBOX, Optional.empty()); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .delete(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override RestconfStrategy testPatchMergePutContainerStrategy() { - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -230,7 +232,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT .when(netconfService).commit(); doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService) .delete(LogicalDatastoreType.CONFIGURATION, CREATE_AND_DELETE_TARGET); - return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService); + return new NetconfRestconfStrategy(JUKEBOX_SCHEMA, netconfService, null); } @Override @@ -245,62 +247,62 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT @Override RestconfStrategy readDataConfigTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readAllHavingOnlyConfigTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH); doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).get(PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readAllHavingOnlyNonConfigTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(netconfService).get(PATH_2); doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(PATH_2); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readDataNonConfigTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_2))).when(netconfService).get(PATH_2); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readContainerDataAllTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH); doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(netconfService).get(PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readContainerDataConfigNoValueOfContentTestStrategy() { doReturn(immediateFluentFuture(Optional.of(DATA_3))).when(netconfService).getConfig(PATH); doReturn(immediateFluentFuture(Optional.of(DATA_4))).when(netconfService).get(PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readListDataAllTestStrategy() { doReturn(immediateFluentFuture(Optional.of(LIST_DATA))).when(netconfService).get(PATH_3); doReturn(immediateFluentFuture(Optional.of(LIST_DATA_2))).when(netconfService).getConfig(PATH_3); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readOrderedListDataAllTestStrategy() { doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_1))).when(netconfService).get(PATH_3); doReturn(immediateFluentFuture(Optional.of(ORDERED_MAP_NODE_2))).when(netconfService).getConfig(PATH_3); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readUnkeyedListDataAllTestStrategy() { doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_1))).when(netconfService).get(PATH_3); doReturn(immediateFluentFuture(Optional.of(UNKEYED_LIST_NODE_2))).when(netconfService).getConfig(PATH_3); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override @@ -309,7 +311,7 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT .get(LEAF_SET_NODE_PATH); doReturn(immediateFluentFuture(Optional.of(LEAF_SET_NODE_2))).when(netconfService) .getConfig(LEAF_SET_NODE_PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override @@ -318,12 +320,12 @@ public final class NetconfRestconfStrategyTest extends AbstractRestconfStrategyT .get(LEAF_SET_NODE_PATH); doReturn(immediateFluentFuture(Optional.of(ORDERED_LEAF_SET_NODE_2))).when(netconfService) .getConfig(LEAF_SET_NODE_PATH); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } @Override RestconfStrategy readDataWrongPathOrNoContentTestStrategy() { doReturn(immediateFluentFuture(Optional.empty())).when(netconfService).getConfig(PATH_2); - return new NetconfRestconfStrategy(mockSchemaContext, netconfService); + return new NetconfRestconfStrategy(mockSchemaContext, netconfService, null); } } -- 2.36.6