Disconnect CreateStreamUtil from NormalizedNodePayload 71/107071/4
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 25 Jul 2023 22:57:11 +0000 (00:57 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 25 Jul 2023 23:47:04 +0000 (01:47 +0200)
CreateStreamUtil really implements RPCs and as such it does not require
all the context provided by NormalizedNodePayload. Refactor its methods
to properly mirror RPC invocations.

Change-Id: I4500af63387c316fa7a6d0b42be563450895404a
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtil.java
restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImpl.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/CreateStreamUtilTest.java

index ab4c4aee5d6efe3d8f3a5902e31f599412b72671..de6717c08f380b092f6bbd1d985373cdb2d89130 100644 (file)
@@ -20,7 +20,6 @@ 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.legacy.NormalizedNodePayload;
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfStreamsConstants;
 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.DeviceNotificationListenerAdaptor;
 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
@@ -87,18 +86,18 @@ final class CreateStreamUtil {
     /**
      * Create data-change-event stream with POST operation via RPC.
      *
-     * @param payload      Input of RPC - example in JSON (data-change-event stream):
-     *                     <pre>
-     *                     {@code
-     *                         {
-     *                             "input": {
-     *                                 "path": "/toaster:toaster/toaster:toasterStatus",
-     *                                 "sal-remote-augment:datastore": "OPERATIONAL",
-     *                                 "sal-remote-augment:scope": "ONE"
-     *                             }
-     *                         }
-     *                     }
-     *                     </pre>
+     * @param input Input of RPC - example in JSON (data-change-event stream):
+     *              <pre>
+     *              {@code
+     *                  {
+     *                      "input": {
+     *                          "path": "/toaster:toaster/toaster:toasterStatus",
+     *                          "sal-remote-augment:datastore": "OPERATIONAL",
+     *                          "sal-remote-augment:scope": "ONE"
+     *                      }
+     *                  }
+     *              }
+     *              </pre>
      * @param refSchemaCtx Reference to {@link EffectiveModelContext}.
      * @return {@link DOMRpcResult} - Output of RPC - example in JSON:
      *     <pre>
@@ -112,16 +111,15 @@ final class CreateStreamUtil {
      *     </pre>
      */
     // FIXME: this really should be a normal RPC implementation
-    static DOMRpcResult createDataChangeNotifiStream(final NormalizedNodePayload payload,
+    static DOMRpcResult createDataChangeNotifiStream(final ContainerNode input,
             final EffectiveModelContext refSchemaCtx) {
         // parsing out of container with settings and path
-        final ContainerNode data = (ContainerNode) requireNonNull(payload).getData();
-        final YangInstanceIdentifier path = preparePath(data);
+        final YangInstanceIdentifier path = preparePath(input);
 
         // building of stream name
         final StringBuilder streamNameBuilder = new StringBuilder(
-                prepareDataChangeNotifiStreamName(path, requireNonNull(refSchemaCtx), data));
-        final NotificationOutputType outputType = prepareOutputType(data);
+                prepareDataChangeNotifiStreamName(path, requireNonNull(refSchemaCtx), input));
+        final NotificationOutputType outputType = prepareOutputType(input);
         if (outputType.equals(NotificationOutputType.JSON)) {
             streamNameBuilder.append('/').append(outputType.getName());
         }
@@ -141,19 +139,17 @@ final class CreateStreamUtil {
      * Create device notification stream.
      *
      * @param baseUrl base Url
-     * @param payload data
+     * @param input RPC input
      * @param streamUtil stream utility
      * @param mountPointService dom mount point service
      * @return {@link DOMRpcResult} - Output of RPC - example in JSON
      */
-    static DOMRpcResult createDeviceNotificationListener(final String baseUrl, final NormalizedNodePayload payload,
+    static DOMRpcResult createDeviceNotificationListener(final String baseUrl, final ContainerNode input,
             final SubscribeToStreamUtil streamUtil, final DOMMountPointService mountPointService) {
         // parsing out of container with settings and path
         // FIXME: ugly cast
-        final ContainerNode data = (ContainerNode) requireNonNull(payload).getData();
-        // FIXME: ugly cast
         final YangInstanceIdentifier path =
-            (YangInstanceIdentifier) data.findChildByArg(DEVICE_NOTIFICATION_PATH_NODEID)
+            (YangInstanceIdentifier) input.findChildByArg(DEVICE_NOTIFICATION_PATH_NODEID)
                 .map(DataContainerChild::body)
                 .orElseThrow(() -> new RestconfDocumentedException("No path specified", ErrorType.APPLICATION,
                     ErrorTag.DATA_MISSING));
@@ -190,7 +186,7 @@ final class CreateStreamUtil {
         }
 
         final DeviceNotificationListenerAdaptor notificationListenerAdapter = ListenersBroker.getInstance()
-            .registerDeviceNotificationListener(deviceName, prepareOutputType(data), mountModelContext,
+            .registerDeviceNotificationListener(deviceName, prepareOutputType(input), mountModelContext,
                 mountPointService, mountPoint.getIdentifier());
         notificationListenerAdapter.listen(mountNotifService, notificationPaths);
 
index 0914ce97e7d89f1f70321ebc539a971acd950b35..e8c788874755daba60fac89cd4db0d22e6adce7b 100644 (file)
@@ -42,7 +42,6 @@ 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.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
@@ -77,20 +76,22 @@ public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperat
         final DOMMountPoint mountPoint = context.getMountPoint();
         final SchemaNode schema = context.getSchemaNode();
         final QName rpcName = schema.getQName();
+        final ContainerNode rpcInput = (ContainerNode) payload.getData();
 
         final ListenableFuture<? extends DOMRpcResult> future;
         if (mountPoint == null) {
             if (CreateDataChangeEventSubscription.QNAME.equals(rpcName)) {
-                future = Futures.immediateFuture(CreateStreamUtil.createDataChangeNotifiStream(payload, schemaContext));
+                future = Futures.immediateFuture(
+                    CreateStreamUtil.createDataChangeNotifiStream(rpcInput, schemaContext));
             } else if (SubscribeDeviceNotification.QNAME.equals(rpcName)) {
                 final String baseUrl = streamUtils.prepareUriByStreamName(uriInfo, "").toString();
-                future = Futures.immediateFuture(CreateStreamUtil.createDeviceNotificationListener(baseUrl, payload,
+                future = Futures.immediateFuture(CreateStreamUtil.createDeviceNotificationListener(baseUrl, rpcInput,
                     streamUtils, mountPointService));
             } else {
-                future = invokeRpc((ContainerNode)payload.getData(), rpcName, rpcService);
+                future = invokeRpc(rpcInput, rpcName, rpcService);
             }
         } else {
-            future = invokeRpc(payload.getData(), rpcName, mountPoint);
+            future = invokeRpc(rpcInput, rpcName, mountPoint);
         }
 
         Futures.addCallback(future, new FutureCallback<DOMRpcResult>() {
@@ -127,9 +128,9 @@ public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperat
      * @return {@link DOMRpcResult}
      */
     @VisibleForTesting
-    static ListenableFuture<? extends DOMRpcResult> invokeRpc(final NormalizedNode data, final QName rpc,
+    static ListenableFuture<? extends DOMRpcResult> invokeRpc(final ContainerNode data, final QName rpc,
             final DOMMountPoint mountPoint) {
-        return invokeRpc((ContainerNode) data, rpc, mountPoint.getService(DOMRpcService.class).orElseThrow(() -> {
+        return invokeRpc(data, rpc, mountPoint.getService(DOMRpcService.class).orElseThrow(() -> {
             final String errmsg = "RPC service is missing.";
             LOG.debug(errmsg);
             return new RestconfDocumentedException(errmsg);
@@ -139,16 +140,15 @@ public class RestconfInvokeOperationsServiceImpl implements RestconfInvokeOperat
     /**
      * Invoke rpc.
      *
-     * @param data input data
+     * @param input input data
      * @param rpc RPC type
      * @param rpcService rpc service to invoke rpc
      * @return {@link DOMRpcResult}
      */
     @VisibleForTesting
-    static ListenableFuture<? extends DOMRpcResult> invokeRpc(final ContainerNode data, final QName rpc,
+    static ListenableFuture<? extends DOMRpcResult> invokeRpc(final ContainerNode input, final QName rpc,
             final DOMRpcService rpcService) {
-        return Futures.catching(rpcService.invokeRpc(rpc, nonnullInput(rpc, data)),
-            DOMRpcException.class,
+        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());
index 21ba3ac595b0c8113932715215d26c50ed3aa279..27648761a291393bda883b54dd0c0d56abbd8df6 100644 (file)
@@ -20,16 +20,14 @@ 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.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
-import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
 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.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
@@ -38,8 +36,6 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
 @RunWith(MockitoJUnitRunner.StrictStubs.class)
@@ -57,12 +53,10 @@ public class CreateStreamUtilTest {
             prepareDomPayload("create-data-change-event-subscription", RpcDefinition::getInput, "toaster", "path"),
             SCHEMA_CTX);
         assertEquals(List.of(), result.errors());
-        final NormalizedNode testedNn = result.value();
-        assertNotNull(testedNn);
-        final NormalizedNodePayload contextRef = prepareDomPayload("create-data-change-event-subscription",
+        assertEquals(prepareDomPayload("create-data-change-event-subscription",
             RpcDefinition::getOutput,
-            "data-change-event-subscription/toaster:toaster/datastore=CONFIGURATION/scope=BASE", "stream-name");
-        assertEquals(contextRef.getData(), testedNn);
+            "data-change-event-subscription/toaster:toaster/datastore=CONFIGURATION/scope=BASE", "stream-name"),
+            result.value());
     }
 
     @Test
@@ -91,7 +85,7 @@ public class CreateStreamUtilTest {
         assertEquals("Instance identifier was not normalized correctly", error.getErrorMessage());
     }
 
-    private static NormalizedNodePayload prepareDomPayload(final String rpcName,
+    private static ContainerNode prepareDomPayload(final String rpcName,
             final Function<RpcDefinition, ContainerLike> rpcToContainer, final String toasterValue,
             final String inputOutputName) {
         final Module rpcModule = SCHEMA_CTX.findModules("sal-remote").iterator().next();
@@ -118,11 +112,9 @@ public class CreateStreamUtilTest {
             o = toasterValue;
         }
 
-        return NormalizedNodePayload.of(InstanceIdentifierContext.ofStack(
-            SchemaInferenceStack.of(SCHEMA_CTX, Absolute.of(rpcQName, containerSchemaNode.getQName()))),
-            Builders.containerBuilder()
-                .withNodeIdentifier(new NodeIdentifier(containerSchemaNode.getQName()))
-                .withChild(ImmutableNodes.leafNode(lfQName, o))
-                .build());
+        return Builders.containerBuilder()
+            .withNodeIdentifier(new NodeIdentifier(containerSchemaNode.getQName()))
+            .withChild(ImmutableNodes.leafNode(lfQName, o))
+            .build();
     }
 }