Add RemoteDeviceServices 53/103653/10
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 10 Dec 2022 14:52:08 +0000 (15:52 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 14 Dec 2022 19:50:06 +0000 (20:50 +0100)
Centralize services to allow their being partially implemented. Also
clean up device instantiation, so that we get some clarity as to what
is (mostly) going on.

JIRA: NETCONF-914
Change-Id: I4195ff5b94b2d4fb5f074ae86fd7b4e6b0ad7f9d
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
17 files changed:
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/MasterSalFacade.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/SlaveSalFacade.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/actors/NetconfNodeActor.java
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/RemoteDeviceHandler.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/RemoteDeviceServices.java [new file with mode: 0644]
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDevice.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/SchemalessNetconfDevice.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/KeepaliveSalFacade.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalFacade.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalProvider.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/NetconfDeviceTest.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/SchemalessNetconfDeviceTest.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/KeepaliveSalFacadeResponseWaitingTest.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/KeepaliveSalFacadeTest.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/MountInstanceTest.java
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/sal/NetconfDeviceSalFacadeTest.java

index 7f8d5bed5a03f627194bf4b5805f04e9898a6885..f1270f4efe7b99a37f9079676585e0e185a39eb3 100644 (file)
@@ -17,19 +17,17 @@ import akka.pattern.Patterns;
 import akka.util.Timeout;
 import java.util.List;
 import org.opendaylight.mdsal.binding.api.DataBroker;
-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.DOMNotification;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 import org.opendaylight.netconf.sal.connect.netconf.sal.AbstractNetconfDataTreeService;
 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceDataBroker;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService;
 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.topology.singleton.messages.CreateInitialMasterActorData;
@@ -51,10 +49,9 @@ class MasterSalFacade implements RemoteDeviceHandler, AutoCloseable {
 
     private NetconfDeviceSchema currentSchema = null;
     private NetconfSessionPreferences netconfSessionPreferences = null;
-    private DOMRpcService deviceRpc = null;
+    private RemoteDeviceServices deviceServices = null;
     private DOMDataBroker deviceDataBroker = null;
     private NetconfDataTreeService netconfService = null;
-    private DOMActionService deviceAction = null;
 
     MasterSalFacade(final RemoteDeviceId id,
                     final ActorSystem actorSystem,
@@ -71,21 +68,14 @@ class MasterSalFacade implements RemoteDeviceHandler, AutoCloseable {
 
     @Override
     public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-                                  final NetconfSessionPreferences sessionPreferences,
-                                  final DOMRpcService domRpcService, final DOMActionService domActionService) {
-        deviceAction = domActionService;
-        LOG.debug("{}: YANG 1.1 actions are supported in clustered netconf topology, "
-            + "DOMActionService exposed for the device", id);
-        onDeviceConnected(deviceSchema, sessionPreferences, domRpcService);
-    }
-
-    @Override
-    public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-                                  final NetconfSessionPreferences sessionPreferences,
-                                  final DOMRpcService domRpcService) {
+            final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
         currentSchema = requireNonNull(deviceSchema);
-        netconfSessionPreferences = sessionPreferences;
-        deviceRpc = domRpcService;
+        netconfSessionPreferences = requireNonNull(sessionPreferences);
+        deviceServices = requireNonNull(services);
+        if (services.actions() != null) {
+            LOG.debug("{}: YANG 1.1 actions are supported in clustered netconf topology, DOMActionService exposed for "
+                + "the device", id);
+        }
 
         LOG.info("Device {} connected - registering master mount point", id);
 
@@ -137,7 +127,6 @@ class MasterSalFacade implements RemoteDeviceHandler, AutoCloseable {
         final var preferences = requireNonNull(netconfSessionPreferences,
             "Device has no capabilities yet. Probably not fully connected.");
 
-        final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
         deviceDataBroker = newDeviceDataBroker(mountContext, preferences);
         netconfService = newNetconfDataTreeService(mountContext, preferences);
 
@@ -148,17 +137,17 @@ class MasterSalFacade implements RemoteDeviceHandler, AutoCloseable {
         final NetconfDataTreeService proxyNetconfService = new ProxyNetconfDataTreeService(id, masterActorRef,
             actorSystem.dispatcher(), actorResponseWaitTime);
         salProvider.getMountInstance().onTopologyDeviceConnected(mountContext.getEffectiveModelContext(),
-            proxyDataBroker, proxyNetconfService, deviceRpc, notificationService, deviceAction);
+            deviceServices, proxyDataBroker, proxyNetconfService);
     }
 
     protected DOMDataBroker newDeviceDataBroker(final MountPointContext mountContext,
             final NetconfSessionPreferences preferences) {
-        return new NetconfDeviceDataBroker(id, mountContext, deviceRpc, preferences);
+        return new NetconfDeviceDataBroker(id, mountContext, deviceServices.rpcs(), preferences);
     }
 
     protected NetconfDataTreeService newNetconfDataTreeService(final MountPointContext mountContext,
             final NetconfSessionPreferences preferences) {
-        return AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, preferences);
+        return AbstractNetconfDataTreeService.of(id, mountContext, deviceServices.rpcs(), preferences);
     }
 
     private Future<Object> sendInitialDataToActor() {
@@ -170,7 +159,7 @@ class MasterSalFacade implements RemoteDeviceHandler, AutoCloseable {
 
         // send initial data to master actor
         return Patterns.ask(masterActorRef, new CreateInitialMasterActorData(deviceDataBroker, netconfService,
-            sourceIdentifiers, deviceRpc, deviceAction), actorResponseWaitTime);
+            sourceIdentifiers, deviceServices.rpcs(), deviceServices.actions()), actorResponseWaitTime);
     }
 
     private void updateDeviceData() {
index d509921f67bb957c80a5483f07c8ea741c3c1273..b7d44cb03cc71876ae46696d299f86166b70ee20 100644 (file)
@@ -11,11 +11,9 @@ import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
 import akka.util.Timeout;
 import java.util.concurrent.atomic.AtomicBoolean;
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceNotificationService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceSalProvider;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
@@ -37,25 +35,24 @@ public class SlaveSalFacade {
                           final Timeout actorResponseWaitTime,
                           final DOMMountPointService mountPointService) {
         this.id = id;
-        this.salProvider = new NetconfDeviceSalProvider(id, mountPointService);
+        salProvider = new NetconfDeviceSalProvider(id, mountPointService);
         this.actorSystem = actorSystem;
         this.actorResponseWaitTime = actorResponseWaitTime;
     }
 
-    public void registerSlaveMountPoint(final EffectiveModelContext remoteSchemaContext, final DOMRpcService deviceRpc,
-            final DOMActionService deviceAction, final ActorRef masterActorRef) {
+    public void registerSlaveMountPoint(final EffectiveModelContext remoteSchemaContext, final ActorRef masterActorRef,
+            final RemoteDeviceServices services) {
         if (!registered.compareAndSet(false, true)) {
             return;
         }
 
-        final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
         final ProxyDOMDataBroker netconfDeviceDataBroker = new ProxyDOMDataBroker(id, masterActorRef,
             actorSystem.dispatcher(), actorResponseWaitTime);
         final NetconfDataTreeService proxyNetconfService = new ProxyNetconfDataTreeService(id, masterActorRef,
             actorSystem.dispatcher(), actorResponseWaitTime);
 
-        salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, netconfDeviceDataBroker,
-            proxyNetconfService, deviceRpc, notificationService, deviceAction);
+        salProvider.getMountInstance().onTopologyDeviceConnected(remoteSchemaContext, services, netconfDeviceDataBroker,
+            proxyNetconfService);
 
         LOG.info("{}: Slave mount point registered.", id);
     }
index 05ae2a05824b35eb114a3a9b8b29a66eedb21d3d..7cc0fa7fbfb066d3f33595f97d7ca0f45f961c41 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.netconf.topology.singleton.impl.ProxyDOMActionService;
 import org.opendaylight.netconf.topology.singleton.impl.ProxyDOMRpcService;
@@ -105,10 +106,10 @@ public class NetconfNodeActor extends AbstractUntypedActor {
                                final DOMMountPointService mountPointService) {
         this.setup = setup;
         this.id = id;
-        this.schemaRegistry = setup.getSchemaResourcesDTO().getSchemaRegistry();
-        this.schemaRepository = setup.getSchemaResourcesDTO().getSchemaRepository();
+        schemaRegistry = setup.getSchemaResourcesDTO().getSchemaRegistry();
+        schemaRepository = setup.getSchemaResourcesDTO().getSchemaRepository();
         this.actorResponseWaitTime = actorResponseWaitTime;
-        this.writeTxIdleTimeout = setup.getIdleTimeout();
+        writeTxIdleTimeout = setup.getIdleTimeout();
         this.mountPointService = mountPointService;
     }
 
@@ -117,15 +118,14 @@ public class NetconfNodeActor extends AbstractUntypedActor {
     public void handleReceive(final Object message) {
         LOG.debug("{}:  received message {}", id, message);
 
-        if (message instanceof CreateInitialMasterActorData) { // master
-            final CreateInitialMasterActorData masterActorData = (CreateInitialMasterActorData) message;
+        if (message instanceof CreateInitialMasterActorData masterActorData) { // master
             sourceIdentifiers = masterActorData.getSourceIndentifiers();
-            this.deviceDataBroker = masterActorData.getDeviceDataBroker();
-            this.netconfService = masterActorData.getNetconfDataTreeService();
+            deviceDataBroker = masterActorData.getDeviceDataBroker();
+            netconfService = masterActorData.getNetconfDataTreeService();
             final DOMDataTreeReadTransaction tx = deviceDataBroker.newReadOnlyTransaction();
             readTxActor = context().actorOf(ReadTransactionActor.props(tx));
-            this.deviceRpc = masterActorData.getDeviceRpc();
-            this.deviceAction = masterActorData.getDeviceAction();
+            deviceRpc = masterActorData.getDeviceRpc();
+            deviceAction = masterActorData.getDeviceAction();
 
             sender().tell(new MasterActorDataInitialized(), self());
             LOG.debug("{}: Master is ready.", id);
@@ -133,8 +133,7 @@ public class NetconfNodeActor extends AbstractUntypedActor {
             setup = ((RefreshSetupMasterActorData) message).getNetconfTopologyDeviceSetup();
             id = ((RefreshSetupMasterActorData) message).getRemoteDeviceId();
             sender().tell(new MasterActorDataInitialized(), self());
-        } else if (message instanceof AskForMasterMountPoint) { // master
-            AskForMasterMountPoint askForMasterMountPoint = (AskForMasterMountPoint) message;
+        } else if (message instanceof AskForMasterMountPoint askForMasterMountPoint) { // master
             // only master contains reference to deviceDataBroker
             if (deviceDataBroker != null) {
                 LOG.debug("{}: Sending RegisterMountPoint reply to {}", id, askForMasterMountPoint.getSlaveActorRef());
@@ -144,8 +143,7 @@ public class NetconfNodeActor extends AbstractUntypedActor {
                 LOG.warn("{}: Received {} but we don't appear to be the master", id, askForMasterMountPoint);
                 sender().tell(new Failure(new NotMasterException(self())), self());
             }
-        } else if (message instanceof YangTextSchemaSourceRequest) { // master
-            final YangTextSchemaSourceRequest yangTextSchemaSourceRequest = (YangTextSchemaSourceRequest) message;
+        } else if (message instanceof YangTextSchemaSourceRequest yangTextSchemaSourceRequest) { // master
             sendYangTextSchemaSourceProxy(yangTextSchemaSourceRequest.getSourceIdentifier(), sender());
         } else if (message instanceof NewReadTransactionRequest) { // master
             sender().tell(new Success(readTxActor), self());
@@ -165,17 +163,14 @@ public class NetconfNodeActor extends AbstractUntypedActor {
             } catch (final Exception t) {
                 sender().tell(new Failure(t), self());
             }
-        } else if (message instanceof InvokeRpcMessage) { // master
-            final InvokeRpcMessage invokeRpcMessage = (InvokeRpcMessage) message;
+        } else if (message instanceof InvokeRpcMessage invokeRpcMessage) { // master
             invokeSlaveRpc(invokeRpcMessage.getSchemaPath().lastNodeIdentifier(),
                 invokeRpcMessage.getNormalizedNodeMessage(), sender());
-        } else if (message instanceof InvokeActionMessage) { // master
-            final InvokeActionMessage invokeActionMessage = (InvokeActionMessage) message;
+        } else if (message instanceof InvokeActionMessage invokeActionMessage) { // master
             LOG.info("InvokeActionMessage Details : {}", invokeActionMessage.toString());
             invokeSlaveAction(invokeActionMessage.getSchemaPath(), invokeActionMessage.getContainerNodeMessage(),
                 invokeActionMessage.getDOMDataTreeIdentifier(), sender());
-        } else if (message instanceof RegisterMountPoint) { //slaves
-            RegisterMountPoint registerMountPoint = (RegisterMountPoint) message;
+        } else if (message instanceof RegisterMountPoint registerMountPoint) { //slaves
             sourceIdentifiers = registerMountPoint.getSourceIndentifiers();
             registerSlaveMountPoint(registerMountPoint.getMasterActorRef());
             sender().tell(new Success(null), self());
@@ -315,14 +310,6 @@ public class NetconfNodeActor extends AbstractUntypedActor {
         resolveSchemaContext(createSchemaContextFactory(masterReference), slaveSalManager, masterReference, 1);
     }
 
-    private DOMRpcService getDOMRpcService(final ActorRef masterReference) {
-        return new ProxyDOMRpcService(setup.getActorSystem(), masterReference, id, actorResponseWaitTime);
-    }
-
-    private DOMActionService getDOMActionService(final ActorRef masterReference) {
-        return new ProxyDOMActionService(setup.getActorSystem(), masterReference, id, actorResponseWaitTime);
-    }
-
     private EffectiveModelContextFactory createSchemaContextFactory(final ActorRef masterReference) {
         final RemoteYangTextSourceProvider remoteYangTextSourceProvider =
                 new ProxyYangTextSourceProvider(masterReference, getContext().dispatcher(), actorResponseWaitTime);
@@ -351,8 +338,10 @@ public class NetconfNodeActor extends AbstractUntypedActor {
                     if (slaveSalManager == localSlaveSalManager) {
                         LOG.info("{}: Schema context resolved: {} - registering slave mount point",
                                 id, result.getModules());
-                        slaveSalManager.registerSlaveMountPoint(result, getDOMRpcService(masterReference),
-                            getDOMActionService(masterReference), masterReference);
+                        final var actorSystem = setup.getActorSystem();
+                        slaveSalManager.registerSlaveMountPoint(result, masterReference, new RemoteDeviceServices(
+                            new ProxyDOMRpcService(actorSystem, masterReference, id, actorResponseWaitTime),
+                            new ProxyDOMActionService(actorSystem, masterReference, id, actorResponseWaitTime)));
                     }
                 });
             }
index ba474efedafd16156165fd5c116d6235f36ccb35..48002955457463c75d13e039c40bf5d3389478eb 100644 (file)
@@ -98,6 +98,7 @@ import org.opendaylight.mdsal.singleton.dom.impl.DOMClusterSingletonServiceProvi
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.nettyutil.ReconnectFuture;
 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
@@ -389,7 +390,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
             new EmptyMountPointContext(deviceSchemaContext)),
             NetconfSessionPreferences.fromStrings(
                 List.of(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString())),
-            deviceRpcService.getRpcService());
+            new RemoteDeviceServices(deviceRpcService.getRpcService(), null));
 
         final var masterMountPoint = awaitMountPoint(masterMountPointService);
 
@@ -465,7 +466,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
         masterSalFacade.onDeviceConnected(new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(),
             new EmptyMountPointContext(deviceSchemaContext)), NetconfSessionPreferences.fromStrings(List.of(
                     NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString())),
-                deviceRpcService.getRpcService());
+                new RemoteDeviceServices(deviceRpcService.getRpcService(), null));
 
         verify(masterMountPointListener, timeout(5000)).onMountPointCreated(yangNodeInstanceId);
 
index b7e3945cc15864b86e56db35bded6507189e50db..9e3f24a5ff51d9cd117645fd2bf8c68b41d47185 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.netconf.sal.connect.api;
 
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
 
@@ -17,28 +15,12 @@ public interface RemoteDeviceHandler extends AutoCloseable {
     /**
      * When device connected, init new mount point with specific schema context and DOM services.
      *
-     * @param deviceSchema {@link NetconfDeviceSchema} of connected device
-     * @param sessionPreferences session of device
-     * @param deviceRpc - {@link DOMRpcService} of device
+     * @param deviceSchema {@link NetconfDeviceSchema} of connected device
+     * @param sessionPreferences session of device
+     * @param services {@link RemoteDeviceServices} available
      */
-    default void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-            final NetconfSessionPreferences sessionPreferences, final DOMRpcService deviceRpc) {
-        // DO NOTHING
-    }
-
-    /**
-     * When device connected, init new mount point with specific schema context and DOM services.
-     *
-     * @param deviceSchema - {@link NetconfDeviceSchema} of connected device
-     * @param sessionPreferences - session of device
-     * @param deviceRpc - {@link DOMRpcService} of device
-     * @param deviceAction - {@link DOMActionService} of device
-     */
-    default void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-            final NetconfSessionPreferences sessionPreferences,
-            final DOMRpcService deviceRpc, final DOMActionService deviceAction) {
-        // DO NOTHING
-    }
+    void onDeviceConnected(NetconfDeviceSchema deviceSchema, NetconfSessionPreferences sessionPreferences,
+            RemoteDeviceServices services);
 
     // FIXME: document this node
     void onDeviceDisconnected();
diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/RemoteDeviceServices.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/api/RemoteDeviceServices.java
new file mode 100644 (file)
index 0000000..ec784a0
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 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.netconf.sal.connect.api;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.dom.api.DOMActionService;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+
+/**
+ * Set of interfaces exposed by a {@link RemoteDevice}.
+ */
+public record RemoteDeviceServices(@NonNull DOMRpcService rpcs, @Nullable DOMActionService actions) {
+    public RemoteDeviceServices {
+        requireNonNull(rpcs);
+    }
+}
index d942fb9c3cd9a8d210957a396beac446d918abae..741850a43fa9683ee7348c141e2dced058af82be 100644 (file)
@@ -45,6 +45,7 @@ import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -232,9 +233,10 @@ public class NetconfDevice implements RemoteDevice<NetconfDeviceCommunicator> {
                 resolveBaseSchema(remoteSessionCapabilities.isNotificationsSupported()));
 
             // salFacade.onDeviceConnected has to be called before the notification handler is initialized
-            salFacade.onDeviceConnected(deviceSchema, remoteSessionCapabilities, deviceRpc,
-                    deviceActionFactory == null ? null : deviceActionFactory.createDeviceAction(
-                            messageTransformer, listener, mount.getEffectiveModelContext()));
+            salFacade.onDeviceConnected(deviceSchema, remoteSessionCapabilities,
+                new RemoteDeviceServices(deviceRpc, deviceActionFactory == null ? null
+                    : deviceActionFactory.createDeviceAction(messageTransformer, listener,
+                        mount.getEffectiveModelContext())));
             notificationHandler.onRemoteSchemaUp(messageTransformer);
 
             LOG.info("{}: Netconf connector initialized successfully", id);
index 3c4d466deb193fc0bcbdc5245c861d13e9114d48..3860288031c66659ab502e727738815e8df36d19 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.annotations.VisibleForTesting;
 import org.opendaylight.netconf.api.NetconfMessage;
 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -54,14 +55,13 @@ public class SchemalessNetconfDevice implements RemoteDevice<NetconfDeviceCommun
     @Override
     public void onRemoteSessionUp(final NetconfSessionPreferences remoteSessionCapabilities,
             final NetconfDeviceCommunicator netconfDeviceCommunicator) {
-        final SchemalessNetconfDeviceRpc schemalessNetconfDeviceRpc = new SchemalessNetconfDeviceRpc(id,
-                netconfDeviceCommunicator, rpcTransformer, messageTransformer);
-
         salFacade.onDeviceConnected(
             // FIXME: or bound from base schema rather?
             new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(),
             baseSchemas.getBaseSchema().getMountPointContext()),
-            remoteSessionCapabilities, schemalessNetconfDeviceRpc);
+            remoteSessionCapabilities, new RemoteDeviceServices(
+                new SchemalessNetconfDeviceRpc(id,netconfDeviceCommunicator, rpcTransformer, messageTransformer),
+                null));
     }
 
     @Override
index f454cf3af7a1b28657021c9320f0c6cc25ad9ced..8bce5d4e3ba5c1a8a78b65d18fd57b74207dbc93 100644 (file)
@@ -26,12 +26,12 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -69,7 +69,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
     private final RemoteDeviceId id;
 
     private volatile NetconfDeviceCommunicator listener;
-    private volatile DOMRpcService currentDeviceRpc;
+    private volatile RemoteDeviceServices currentServices;
 
     public KeepaliveSalFacade(final RemoteDeviceId id, final RemoteDeviceHandler salFacade,
             final ScheduledExecutorService executor, final long keepaliveDelaySeconds,
@@ -101,7 +101,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
      */
     private synchronized void stopKeepalives() {
         keepaliveTask.disableKeepalive();
-        currentDeviceRpc = null;
+        currentServices = null;
     }
 
     void reconnect() {
@@ -113,17 +113,15 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
 
     @Override
     public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-            final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
-        onDeviceConnected(deviceSchema, netconfSessionPreferences, deviceRpc, null);
-    }
+            final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
+        currentServices = requireNonNull(services);
 
-    @Override
-    public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-            final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc,
-            final DOMActionService deviceAction) {
-        currentDeviceRpc = requireNonNull(deviceRpc);
-        salFacade.onDeviceConnected(deviceSchema, netconfSessionPreferences,
-            new KeepaliveDOMRpcService(deviceRpc), deviceAction);
+        final var devAction = services.actions();
+        // FIXME: wrap with keepalive
+        final var kaAction = devAction;
+
+        salFacade.onDeviceConnected(deviceSchema, sessionPreferences,
+            new RemoteDeviceServices(new KeepaliveDOMRpcService(services.rpcs()), kaAction));
 
         LOG.debug("{}: Netconf session initiated, starting keepalives", id);
         LOG.trace("{}: Scheduling keepalives every {}s", id, keepaliveDelaySeconds);
@@ -213,8 +211,8 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
                 return;
             }
 
-            final var deviceRpc = currentDeviceRpc;
-            if (deviceRpc == null) {
+            final var localServices = currentServices;
+            if (localServices == null) {
                 // deviceRpc is null, which means we hit the reconnect window and attempted to send keepalive while
                 // we were reconnecting. Next keepalive will be scheduled after reconnect so no action necessary here.
                 LOG.debug("{}: Skipping keepalive while reconnecting", id);
@@ -222,7 +220,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
             }
 
             LOG.trace("{}: Invoking keepalive RPC", id);
-            final var deviceFuture = deviceRpc.invokeRpc(NETCONF_GET_CONFIG_QNAME, KEEPALIVE_PAYLOAD);
+            final var deviceFuture = localServices.rpcs().invokeRpc(NETCONF_GET_CONFIG_QNAME, KEEPALIVE_PAYLOAD);
 
             lastActivity = now;
             Futures.addCallback(deviceFuture, this, MoreExecutors.directExecutor());
index 2c8548e550855d2d155a4e9e6b42f94283eef5be..4252c03a852adb8e0d513ab722ed213616dea777 100644 (file)
@@ -11,12 +11,11 @@ import com.google.common.annotations.VisibleForTesting;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -30,9 +29,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev19
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,20 +64,18 @@ public final class NetconfDeviceSalFacade implements RemoteDeviceHandler, AutoCl
 
     @Override
     public synchronized void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-            final NetconfSessionPreferences sessionPreferences, final DOMRpcService deviceRpc,
-            final DOMActionService deviceAction) {
-        final MountPointContext mountContext = deviceSchema.mountContext();
-        final EffectiveModelContext schemaContext = mountContext.getEffectiveModelContext();
-
-        final NetconfDeviceDataBroker netconfDeviceDataBroker =
-                new NetconfDeviceDataBroker(id, mountContext, deviceRpc, sessionPreferences);
-        final NetconfDataTreeService netconfService =
-                AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, sessionPreferences);
-        registerLockListener(netconfDeviceDataBroker, netconfService);
-        final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
-
-        salProvider.getMountInstance().onTopologyDeviceConnected(schemaContext, netconfDeviceDataBroker, netconfService,
-            deviceRpc, notificationService, deviceAction);
+            final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
+        final var mountContext = deviceSchema.mountContext();
+        final var modelContext = mountContext.getEffectiveModelContext();
+
+        final var deviceRpc = services.rpcs();
+        // FIXME: instanceof DOMRpcService, as it might be others
+        final var netconfDataBroker = new NetconfDeviceDataBroker(id, mountContext, deviceRpc, sessionPreferences);
+        final var netconfDataTree = AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, sessionPreferences);
+        registerLockListener(netconfDataBroker, netconfDataTree);
+
+        salProvider.getMountInstance().onTopologyDeviceConnected(modelContext, services, netconfDataBroker,
+            netconfDataTree);
         salProvider.getTopologyDatastoreAdapter().updateDeviceData(true, deviceSchema.capabilities());
     }
 
index 55ede4ccc121e0338ab03d04058e0611bb4917e7..9109ee4bcb5fba56fc0fd784130637c7e4b9e337 100644 (file)
@@ -22,6 +22,7 @@ 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;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
@@ -85,9 +86,16 @@ public class NetconfDeviceSalProvider implements AutoCloseable {
             this.id = requireNonNull(id);
         }
 
+        public void onTopologyDeviceConnected(final EffectiveModelContext initialCtx,
+                final RemoteDeviceServices services, final DOMDataBroker broker,
+                final NetconfDataTreeService dataTreeService) {
+            onTopologyDeviceConnected(initialCtx, services, new NetconfDeviceNotificationService(), broker,
+                dataTreeService);
+        }
+
         public synchronized void onTopologyDeviceConnected(final EffectiveModelContext initialCtx,
-                final DOMDataBroker broker, final NetconfDataTreeService netconfService, final DOMRpcService rpc,
-                final NetconfDeviceNotificationService newNotificationService, final DOMActionService deviceAction) {
+                final RemoteDeviceServices services, final NetconfDeviceNotificationService newNotificationService,
+                final DOMDataBroker broker, final NetconfDataTreeService dataTreeService) {
             requireNonNull(mountService, "Closed");
             checkState(topologyRegistration == null, "Already initialized");
 
@@ -98,14 +106,15 @@ public class NetconfDeviceSalProvider implements AutoCloseable {
             if (broker != null) {
                 mountBuilder.addService(DOMDataBroker.class, broker);
             }
-            mountBuilder.addService(DOMRpcService.class, rpc);
-            mountBuilder.addService(DOMNotificationService.class, newNotificationService);
-            if (deviceAction != null) {
-                mountBuilder.addService(DOMActionService.class, deviceAction);
+            mountBuilder.addService(DOMRpcService.class, services.rpcs());
+            final var actions = services.actions();
+            if (actions != null) {
+                mountBuilder.addService(DOMActionService.class, actions);
             }
-            if (netconfService != null) {
-                mountBuilder.addService(NetconfDataTreeService.class, netconfService);
+            if (dataTreeService != null) {
+                mountBuilder.addService(NetconfDataTreeService.class, dataTreeService);
             }
+            mountBuilder.addService(DOMNotificationService.class, newNotificationService);
             notificationService = newNotificationService;
 
             topologyRegistration = mountBuilder.register();
index eaf8ff1352a90d4358169d0c1837919530046ae2..43bf865e5ef32d498003db30328d9edb6e2fa8f1 100644 (file)
@@ -13,7 +13,6 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyCollection;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
@@ -45,10 +44,8 @@ import java.util.Set;
 import java.util.concurrent.Executors;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
 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.api.NetconfMessage;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
@@ -56,10 +53,10 @@ import org.opendaylight.netconf.api.xml.XmlUtil;
 import org.opendaylight.netconf.sal.connect.api.MessageTransformer;
 import org.opendaylight.netconf.sal.connect.api.NetconfDeviceSchemasResolver;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
@@ -158,7 +155,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
         device.onRemoteSessionUp(sessionCaps, listener);
 
         verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
-            any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class), isNull());
+            any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
         verify(schemaFactory, times(2)).createEffectiveModelContext(anyCollection());
     }
 
@@ -242,11 +239,11 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
                 .build();
         // Monitoring supported
         final NetconfSessionPreferences sessionCaps =
-                getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
+                getSessionCaps(true, List.of(TEST_CAPABILITY, TEST_CAPABILITY2));
         device.onRemoteSessionUp(sessionCaps, listener);
 
         verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
-            any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class), isNull());
+            any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
         verify(schemaFactory, times(1)).createEffectiveModelContext(anyCollection());
     }
 
@@ -326,8 +323,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         verify(schemaContextProviderFactory, timeout(5000)).createEffectiveModelContext(any(Collection.class));
         verify(facade, timeout(5000)).onDeviceConnected(
-                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
-                isNull());
+                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
 
         device.onRemoteSessionDown();
         verify(facade, timeout(5000)).onDeviceDisconnected();
@@ -336,8 +332,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         verify(schemaContextProviderFactory, timeout(5000).times(2)).createEffectiveModelContext(any(Collection.class));
         verify(facade, timeout(5000).times(2)).onDeviceConnected(
-                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
-                isNull());
+                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
     }
 
     @Test
@@ -368,7 +363,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
         //complete schema setup
         schemaFuture.set(SCHEMA_CONTEXT);
         //facade.onDeviceDisconnected() was called, so facade.onDeviceConnected() shouldn't be called anymore
-        verify(facade, after(1000).never()).onDeviceConnected(any(), any(), any(), any(DOMActionService.class));
+        verify(facade, after(1000).never()).onDeviceConnected(any(), any(), any(RemoteDeviceServices.class));
     }
 
     @Test
@@ -401,7 +396,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         final ArgumentCaptor<NetconfDeviceSchema> argument =  ArgumentCaptor.forClass(NetconfDeviceSchema.class);
         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
-            any(DOMRpcService.class), isNull());
+            any(RemoteDeviceServices.class));
         argument.getValue().capabilities().resolvedCapabilities()
                 .forEach(entry -> assertEquals("Builded 'AvailableCapability' schemas should match input capabilities.",
                         moduleBasedCaps.get(
@@ -432,7 +427,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
-                any(DOMRpcService.class), isNull());
+                any(RemoteDeviceServices.class));
 
         List<String> notificationModulesName = Arrays.asList(
                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
@@ -471,7 +466,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
-                any(DOMRpcService.class), isNull());
+                any(RemoteDeviceServices.class));
         final NetconfDeviceCapabilities netconfDeviceCaps = argument.getValue().capabilities();
 
         List<String> notificationModulesName = List.of(
@@ -516,10 +511,10 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
 
         final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
         verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
-                any(DOMRpcService.class), isNull());
+                any(RemoteDeviceServices.class));
         final Set<AvailableCapability> resolvedCapabilities = argument.getValue().capabilities().resolvedCapabilities();
 
-        List<String> notificationModulesName = Arrays.asList(
+        List<String> notificationModulesName = List.of(
                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
                         .$YangModuleInfoImpl.getInstance().getName().toString(),
                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
@@ -540,8 +535,7 @@ public class NetconfDeviceTest extends AbstractTestModelTest {
     private static RemoteDeviceHandler getFacade() throws Exception {
         final RemoteDeviceHandler remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
         doNothing().when(remoteDeviceHandler).onDeviceConnected(
-                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class),
-                any(DOMActionService.class));
+                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
         doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
         doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
         return remoteDeviceHandler;
index f2e89eb75e73724b2085aa4d9f425d6ddb26fbc9..0b080142044010070e3b2324b216cec4fb670247 100644 (file)
@@ -20,13 +20,12 @@ import java.util.Collection;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
-import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.api.NetconfMessage;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfDeviceRpc;
 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.SchemalessMessageTransformer;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
@@ -56,7 +55,7 @@ public class SchemalessNetconfDeviceTest extends AbstractBaseSchemasTest {
 
         device.onRemoteSessionUp(sessionCaps, listener);
         verify(facade).onDeviceConnected(
-                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
 
         device.onNotification(netconfMessage);
         verify(facade).onNotification(isNull());
@@ -71,7 +70,7 @@ public class SchemalessNetconfDeviceTest extends AbstractBaseSchemasTest {
     private static RemoteDeviceHandler getFacade() throws Exception {
         final RemoteDeviceHandler remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
         doNothing().when(remoteDeviceHandler).onDeviceConnected(
-                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
+                any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(RemoteDeviceServices.class));
         doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
         doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
         return remoteDeviceHandler;
index 2ea5c9554865ac514da56ccf6ec6d8811f09bad3..173ba4498c50d13d073592301c73f502c1d2242a 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.netconf.sal.connect.netconf.sal;
 
+import static java.util.Objects.requireNonNull;
 import static org.mockito.Mockito.after;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
@@ -26,12 +27,12 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
-import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
 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.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -90,7 +91,7 @@ public class KeepaliveSalFacadeResponseWaitingTest {
             .withNodeIdentifier(NetconfMessageTransformUtil.NETCONF_RUNNING_NODEID)
             .build()));
 
-        keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+        keepaliveSalFacade.onDeviceConnected(null, null, new RemoteDeviceServices(deviceRpc, null));
 
         //Invoke general RPC on simulated local facade without args (or with null args). Will be returned
         //settableFuture variable without any set value. WaitingShaduler in keepalive sal facade should wait for any
@@ -105,17 +106,17 @@ public class KeepaliveSalFacadeResponseWaitingTest {
     }
 
     private static final class LocalNetconfSalFacade implements RemoteDeviceHandler {
-        private DOMRpcService localDeviceRpc;
+        private volatile RemoteDeviceServices currentServices;
 
         @Override
         public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
-                final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService currentDeviceRpc,
-                final DOMActionService deviceAction) {
-            localDeviceRpc = currentDeviceRpc;
+                final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
+            currentServices = requireNonNull(services);
         }
 
         @Override
         public void onDeviceDisconnected() {
+            currentServices = null;
         }
 
         @Override
@@ -131,8 +132,9 @@ public class KeepaliveSalFacadeResponseWaitingTest {
         }
 
         public void invokeNullRpc() {
-            if (localDeviceRpc != null) {
-                localDeviceRpc.invokeRpc(null, null);
+            final var local = currentServices;
+            if (local != null) {
+                local.rpcs().invokeRpc(null, null);
             }
         }
     }
index 1f5abea5656f475268040fdec5c7520f1fd46a33..24c7265dae2fa22dba5bcf3f42696f0aa0a0230a 100644 (file)
@@ -26,10 +26,10 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
-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.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
@@ -64,7 +64,7 @@ public class KeepaliveSalFacadeTest {
         executorServiceSpy = Executors.newScheduledThreadPool(1);
 
         doNothing().when(listener).disconnect();
-        doNothing().when(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(DOMRpcService.class), isNull());
+        doNothing().when(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
 
         keepaliveSalFacade =
                 new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 1L, 1L);
@@ -82,10 +82,10 @@ public class KeepaliveSalFacadeTest {
             .withNodeIdentifier(NetconfMessageTransformUtil.NETCONF_RUNNING_NODEID)
             .build()))).when(deviceRpc).invokeRpc(any(QName.class), any(ContainerNode.class));
 
-        keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+        final var services = new RemoteDeviceServices(deviceRpc, null);
+        keepaliveSalFacade.onDeviceConnected(null, null, services);
 
-        verify(underlyingSalFacade).onDeviceConnected(
-                isNull(), isNull(), any(DOMRpcService.class), isNull());
+        verify(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
 
         verify(deviceRpc, timeout(15000).times(5)).invokeRpc(any(QName.class), any(ContainerNode.class));
     }
@@ -96,9 +96,9 @@ public class KeepaliveSalFacadeTest {
         doReturn(FluentFutures.immediateFailedFluentFuture(new IllegalStateException("illegal-state")))
                 .when(deviceRpc).invokeRpc(any(QName.class), any(ContainerNode.class));
 
-        keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+        keepaliveSalFacade.onDeviceConnected(null, null, new RemoteDeviceServices(deviceRpc, null));
 
-        verify(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(DOMRpcService.class), isNull());
+        verify(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
 
         // Should disconnect the session
         verify(listener, timeout(15000).times(1)).disconnect();
@@ -108,15 +108,14 @@ public class KeepaliveSalFacadeTest {
     @Test
     public void testKeepaliveSuccessWithRpcError() {
 
-        final DOMRpcResult rpcSuccessWithError = new DefaultDOMRpcResult(mock(RpcError.class));
+        final var rpcSuccessWithError = new DefaultDOMRpcResult(mock(RpcError.class));
 
         doReturn(FluentFutures.immediateFluentFuture(rpcSuccessWithError))
                 .when(deviceRpc).invokeRpc(any(QName.class), any(ContainerNode.class));
 
-        keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
-
-        verify(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(DOMRpcService.class), isNull());
+        keepaliveSalFacade.onDeviceConnected(null, null, new RemoteDeviceServices(deviceRpc, null));
 
+        verify(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
 
         // Shouldn't disconnect the session
         verify(listener, times(0)).disconnect();
@@ -125,8 +124,8 @@ public class KeepaliveSalFacadeTest {
 
     @Test
     public void testNonKeepaliveRpcFailure() throws Exception {
-        doAnswer(invocation -> proxyRpc = invocation.getArgument(2))
-                .when(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(DOMRpcService.class), isNull());
+        doAnswer(invocation -> proxyRpc = invocation.getArgument(2, RemoteDeviceServices.class).rpcs())
+                .when(underlyingSalFacade).onDeviceConnected(isNull(), isNull(), any(RemoteDeviceServices.class));
 
         doReturn(FluentFutures.immediateFailedFluentFuture(new IllegalStateException("illegal-state")))
                 .when(deviceRpc).invokeRpc(any(QName.class), any(ContainerNode.class));
@@ -135,7 +134,7 @@ public class KeepaliveSalFacadeTest {
                 new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, executorServiceSpy, 100L, 1L);
         keepaliveSalFacade.setListener(listener);
 
-        keepaliveSalFacade.onDeviceConnected(null, null, deviceRpc);
+        keepaliveSalFacade.onDeviceConnected(null, null, new RemoteDeviceServices(deviceRpc, null));
 
         proxyRpc.invokeRpc(QName.create("foo", "bar"), mock(ContainerNode.class));
 
index 3a63e17a93fb7d777d10495b1d54d5e9056343f4..b18bd7990dc5f7a5559a9e500080f7b5c46b52ac 100644 (file)
@@ -13,7 +13,6 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.net.InetSocketAddress;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -29,6 +28,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.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.IetfNetconfService;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
@@ -79,8 +79,8 @@ public class MountInstanceTest {
 
     @Test
     public void testOnTopologyDeviceConnected() {
-        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, null, rpcService,
-            notificationService, null);
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, broker, null);
         verify(mountPointBuilder).addService(eq(DOMSchemaService.class), any());
         verify(mountPointBuilder).addService(DOMDataBroker.class, broker);
         verify(mountPointBuilder).addService(DOMRpcService.class, rpcService);
@@ -89,8 +89,8 @@ public class MountInstanceTest {
 
     @Test
     public void testOnTopologyDeviceConnectedWithNetconfService() {
-        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, null, netconfService, rpcService,
-                notificationService, null);
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, null, netconfService);
         verify(mountPointBuilder).addService(eq(DOMSchemaService.class), any());
         verify(mountPointBuilder).addService(NetconfDataTreeService.class, netconfService);
         verify(mountPointBuilder).addService(DOMRpcService.class, rpcService);
@@ -99,31 +99,26 @@ public class MountInstanceTest {
 
     @Test
     public void testOnTopologyDeviceDisconnected() {
-        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, null, rpcService,
-            notificationService, null);
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, broker, null);
         mountInstance.onTopologyDeviceDisconnected();
         verify(registration).close();
-        try {
-            mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, null, rpcService,
-                notificationService, null);
-        } catch (final IllegalStateException e) {
-            LOG.warn("Operation failed.", e);
-            Assert.fail("Topology registration still present after disconnect ");
-        }
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, broker, null);
     }
 
     @Test
     public void testClose() {
-        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, null, rpcService,
-            notificationService, null);
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, broker, null);
         mountInstance.close();
         verify(registration).close();
     }
 
     @Test
     public void testPublishNotification() {
-        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, broker, null, rpcService,
-            notificationService, null);
+        mountInstance.onTopologyDeviceConnected(SCHEMA_CONTEXT, new RemoteDeviceServices(rpcService, null),
+            notificationService, broker, null);
         verify(mountPointBuilder).addService(eq(DOMSchemaService.class), any());
         verify(mountPointBuilder).addService(DOMNotificationService.class, notificationService);
         mountInstance.publish(notification);
index e833f556b858128172aae5c8f6b8c2d218bcae11..15e28983456ae0d33dff9d5083a36240027b9af8 100644 (file)
@@ -11,7 +11,6 @@ package org.opendaylight.netconf.sal.connect.netconf.sal;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -36,6 +35,7 @@ import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.api.RemoteDeviceServices;
 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
@@ -113,15 +113,14 @@ public class NetconfDeviceSalFacadeTest {
         final var netconfSessionPreferences = NetconfSessionPreferences.fromStrings(
             List.of(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString()));
 
-        final DOMRpcService deviceRpc = mock(DOMRpcService.class);
+        final var deviceServices = new RemoteDeviceServices(mock(DOMRpcService.class), null);
         deviceFacade.onDeviceConnected(
             new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(), new EmptyMountPointContext(schemaContext)),
-            netconfSessionPreferences, deviceRpc, null);
+            netconfSessionPreferences, deviceServices);
 
         verifyConnectionStatusUpdate(ConnectionStatus.Connected);
-        verify(mountInstance, times(1)).onTopologyDeviceConnected(eq(schemaContext),
-                any(DOMDataBroker.class), any(NetconfDataTreeService.class), eq(deviceRpc),
-                any(NetconfDeviceNotificationService.class), isNull());
+        verify(mountInstance, times(1)).onTopologyDeviceConnected(eq(schemaContext), eq(deviceServices),
+            any(DOMDataBroker.class), any(NetconfDataTreeService.class));
     }
 
     @Test