Migrate netconf-topology to new transport 53/108253/18
authorRuslan Kashapov <ruslan.kashapov@pantheon.tech>
Mon, 23 Oct 2023 09:38:37 +0000 (12:38 +0300)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 13 Nov 2023 15:33:08 +0000 (16:33 +0100)
Deprecated NetconfClientDispatcher was replaced with
NetconfClientFactory for further migration. The call-home
components were updated only as ancestor component,
reflecting api changes.

JIRA: NETCONF-1108
Change-Id: Iade4fcaf0680d58319427020d1b1894e3c6ac75e
Signed-off-by: Ruslan Kashapov <ruslan.kashapov@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
21 files changed:
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountFactory.java [moved from apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java with 74% similarity]
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountSessionContext.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java
apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountFactoryTest.java [moved from apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java with 93% similarity]
apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java
apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java
apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfNodeContext.java
apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java
apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java
apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java
apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/DefaultNetconfClientConfigurationBuilderFactory.java
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImpl.java [new file with mode: 0644]
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java
apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImplTest.java [new file with mode: 0644]
apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java
netconf/callhome-protocol/src/main/java/org/opendaylight/netconf/callhome/protocol/CallHomeChannelActivator.java
netconf/callhome-protocol/src/main/java/org/opendaylight/netconf/callhome/protocol/CallHomeSessionContext.java
netconf/callhome-protocol/src/main/java/org/opendaylight/netconf/callhome/protocol/tls/CallHomeTlsSessionContext.java

similarity index 74%
rename from apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java
rename to apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountFactory.java
index c0d939973506866389e6ba91ec054f3f8adefbfd..e9933ea88617b230b62dd17186ec0ab7b045a785 100644 (file)
@@ -10,9 +10,9 @@ package org.opendaylight.netconf.callhome.mount;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.FailedFuture;
-import io.netty.util.concurrent.Future;
 import java.net.InetSocketAddress;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
 import org.opendaylight.controller.config.threadpool.ThreadPool;
@@ -21,7 +21,7 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.callhome.protocol.CallHomeChannelActivator;
 import org.opendaylight.netconf.callhome.protocol.CallHomeNetconfSubsystemListener;
 import org.opendaylight.netconf.callhome.protocol.CallHomeProtocolSessionContext;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
@@ -36,16 +36,16 @@ import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Component(service = { CallHomeMountDispatcher.class, CallHomeNetconfSubsystemListener.class }, immediate = true)
+@Component(service = { CallHomeMountFactory.class, CallHomeNetconfSubsystemListener.class }, immediate = true)
 // Non-final for testing
-public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHomeNetconfSubsystemListener {
-    private static final Logger LOG = LoggerFactory.getLogger(CallHomeMountDispatcher.class);
+public class CallHomeMountFactory implements NetconfClientFactory, CallHomeNetconfSubsystemListener {
+    private static final Logger LOG = LoggerFactory.getLogger(CallHomeMountFactory.class);
 
     private final CallHomeMountSessionManager sessionManager = new CallHomeMountSessionManager();
     private final String topologyId;
     private final EventExecutor eventExecutor;
-    private final ScheduledThreadPool keepaliveExecutor;
-    private final ThreadPool processingExecutor;
+    private final ScheduledThreadPool scheduledThreadPool;
+    private final ThreadPool processingThreadPool;
     private final SchemaResourceManager schemaRepositoryProvider;
     private final DataBroker dataBroker;
     private final DOMMountPointService mountService;
@@ -57,40 +57,40 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
     private final BaseNetconfSchemas baseSchemas;
 
 
-    public CallHomeMountDispatcher(final String topologyId, final EventExecutor eventExecutor,
-            final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
+    public CallHomeMountFactory(final String topologyId, final EventExecutor eventExecutor,
+            final ScheduledThreadPool scheduledThreadPool, final ThreadPool processingThreadPool,
             final SchemaResourceManager schemaRepositoryProvider, final BaseNetconfSchemas baseSchemas,
             final DataBroker dataBroker, final DOMMountPointService mountService,
             final NetconfClientConfigurationBuilderFactory builderFactory) {
-        this(topologyId, eventExecutor, keepaliveExecutor, processingExecutor, schemaRepositoryProvider, baseSchemas,
-            dataBroker, mountService, builderFactory, null);
+        this(topologyId, eventExecutor, scheduledThreadPool, processingThreadPool, schemaRepositoryProvider,
+            baseSchemas, dataBroker, mountService, builderFactory, null);
     }
 
     @Activate
-    public CallHomeMountDispatcher(
+    public CallHomeMountFactory(
             @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
             @Reference(target = "(type=global-netconf-ssh-scheduled-executor)")
-                final ScheduledThreadPool keepaliveExecutor,
-            @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingExecutor,
+                final ScheduledThreadPool scheduledThreadPool,
+            @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingThreadPool,
             @Reference final SchemaResourceManager schemaRepositoryProvider,
             @Reference final BaseNetconfSchemas baseSchemas, @Reference final DataBroker dataBroker,
             @Reference final DOMMountPointService mountService,
-            @Reference final NetconfClientConfigurationBuilderFactory builderFactory,
+            @Reference(target = "(type=legacy)") final NetconfClientConfigurationBuilderFactory builderFactory,
             @Reference final DeviceActionFactory deviceActionFactory) {
-        this(NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, eventExecutor, keepaliveExecutor, processingExecutor,
+        this(NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, eventExecutor, scheduledThreadPool, processingThreadPool,
             schemaRepositoryProvider, baseSchemas, dataBroker, mountService, builderFactory, deviceActionFactory);
     }
 
-    public CallHomeMountDispatcher(final String topologyId, final EventExecutor eventExecutor,
-            final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
+    public CallHomeMountFactory(final String topologyId, final EventExecutor eventExecutor,
+            final ScheduledThreadPool scheduledThreadPool, final ThreadPool processingThreadPool,
             final SchemaResourceManager schemaRepositoryProvider, final BaseNetconfSchemas baseSchemas,
             final DataBroker dataBroker, final DOMMountPointService mountService,
             final NetconfClientConfigurationBuilderFactory builderFactory,
             final DeviceActionFactory deviceActionFactory) {
         this.topologyId = topologyId;
         this.eventExecutor = eventExecutor;
-        this.keepaliveExecutor = keepaliveExecutor;
-        this.processingExecutor = processingExecutor;
+        this.scheduledThreadPool = scheduledThreadPool;
+        this.processingThreadPool = processingThreadPool;
         this.schemaRepositoryProvider = schemaRepositoryProvider;
         this.deviceActionFactory = deviceActionFactory;
         this.baseSchemas = requireNonNull(baseSchemas);
@@ -101,15 +101,15 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
 
     @Deprecated
     @Override
-    public Future<NetconfClientSession> createClient(final NetconfClientConfiguration clientConfiguration) {
+    public ListenableFuture<NetconfClientSession> createClient(final NetconfClientConfiguration clientConfiguration) {
         return activateChannel(clientConfiguration);
     }
 
-    private Future<NetconfClientSession> activateChannel(final NetconfClientConfiguration conf) {
+    private ListenableFuture<NetconfClientSession> activateChannel(final NetconfClientConfiguration conf) {
         final InetSocketAddress remoteAddr = conf.getAddress();
         final CallHomeMountSessionContext context = sessionManager().getByAddress(remoteAddr);
         LOG.info("Activating NETCONF channel for ip {} device context {}", remoteAddr, context);
-        return context == null ? new FailedFuture<>(eventExecutor, new NullPointerException())
+        return context == null ? Futures.immediateFailedFuture(new NullPointerException("context is null"))
             : context.activateNetconfChannel(conf.getSessionListener());
     }
 
@@ -130,7 +130,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
 
     @VisibleForTesting
     void createTopology() {
-        topology = new CallHomeTopology(topologyId, this, eventExecutor, keepaliveExecutor, processingExecutor,
+        topology = new CallHomeTopology(topologyId, this, eventExecutor, scheduledThreadPool, processingThreadPool,
                 schemaRepositoryProvider, dataBroker, mountService, builderFactory, baseSchemas, deviceActionFactory);
     }
 
@@ -138,4 +138,9 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
     CallHomeMountSessionManager sessionManager() {
         return sessionManager;
     }
+
+    @Override
+    public void close() throws Exception {
+        // no action
+    }
 }
index d0c5b604c62bc6300da43613db250c949602218a..52c094bc1c3a9b86d492630c9d31a1b286b4a425 100644 (file)
@@ -10,7 +10,7 @@ package org.opendaylight.netconf.callhome.mount;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.MoreObjects;
-import io.netty.util.concurrent.Future;
+import com.google.common.util.concurrent.ListenableFuture;
 import org.opendaylight.netconf.api.NetconfTerminationReason;
 import org.opendaylight.netconf.api.messages.NetconfMessage;
 import org.opendaylight.netconf.callhome.protocol.CallHomeChannelActivator;
@@ -107,7 +107,7 @@ class CallHomeMountSessionContext {
                 .build();
     }
 
-    Future<NetconfClientSession> activateNetconfChannel(final NetconfClientSessionListener sessionListener) {
+    ListenableFuture<NetconfClientSession> activateNetconfChannel(final NetconfClientSessionListener sessionListener) {
         return activator.activate(wrap(sessionListener));
     }
 
index a308e9789d620221cbf1f690a11dcdf6c78f743e..f85a007884bef805b013c9d0d4d2d87ce215e18c 100644 (file)
@@ -13,7 +13,7 @@ import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
 import org.opendaylight.controller.config.threadpool.ThreadPool;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
@@ -24,13 +24,13 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 
 // Non-final for mocking
 public class CallHomeTopology extends AbstractNetconfTopology {
-    public CallHomeTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
-            final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-            final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
+    public CallHomeTopology(final String topologyId, final NetconfClientFactory clientFactory,
+            final EventExecutor eventExecutor, final ScheduledThreadPool scheduledThreadPool,
+            final ThreadPool processingThreadPool, final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final NetconfClientConfigurationBuilderFactory builderFactory, final BaseNetconfSchemas baseSchemas,
             final DeviceActionFactory deviceActionFactory) {
-        super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
+        super(topologyId, clientFactory, eventExecutor, scheduledThreadPool, processingThreadPool,
             schemaRepositoryProvider, dataBroker, mountPointService, builderFactory, deviceActionFactory,
             baseSchemas);
     }
index bb1b3279154e78799b45c7960bf3a1fa4ca10d7c..8134a1501241556ec10ca0816cd5710d1f902dab 100644 (file)
@@ -65,7 +65,7 @@ public final class IetfZeroTouchCallHomeServerProvider
     private static final Logger LOG = LoggerFactory.getLogger(IetfZeroTouchCallHomeServerProvider.class);
 
     private final DataBroker dataBroker;
-    private final CallHomeMountDispatcher mountDispacher;
+    private final CallHomeMountFactory mountDispacher;
     private final CallHomeAuthProviderImpl authProvider;
     private final CallhomeStatusReporter statusReporter;
     private final int port;
@@ -75,15 +75,15 @@ public final class IetfZeroTouchCallHomeServerProvider
 
     @Activate
     public IetfZeroTouchCallHomeServerProvider(@Reference final DataBroker dataBroker,
-            @Reference final CallHomeMountDispatcher mountDispacher) {
+            @Reference final CallHomeMountFactory mountDispacher) {
         // FIXME: make this configurable
         this(dataBroker, mountDispacher, Uint16.valueOf(4334));
     }
 
     public IetfZeroTouchCallHomeServerProvider(final DataBroker dataBroker,
-            final CallHomeMountDispatcher mountDispacher, final Uint16 port) {
+            final CallHomeMountFactory mountFactory, final Uint16 port) {
         this.dataBroker = requireNonNull(dataBroker);
-        this.mountDispacher = requireNonNull(mountDispacher);
+        this.mountDispacher = requireNonNull(mountFactory);
 
         LOG.info("Setting port for call home server to {}", port);
         this.port = port.toJava();
similarity index 93%
rename from apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java
rename to apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountFactoryTest.java
index d3c3c4d375ba82b6982b882531c6752e4e8bf9aa..52746952d3f0bb381b8b5be03df423a44440c7e5 100644 (file)
@@ -7,7 +7,8 @@
  */
 package org.opendaylight.netconf.callhome.mount;
 
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
@@ -16,9 +17,9 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
+import java.util.concurrent.ExecutionException;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
@@ -28,7 +29,6 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.callhome.protocol.CallHomeChannelActivator;
 import org.opendaylight.netconf.callhome.protocol.CallHomeProtocolSessionContext;
-import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
@@ -39,14 +39,14 @@ import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFa
 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.network.topology.topology.Node;
 
-public class CallHomeMountDispatcherTest {
+public class CallHomeMountFactoryTest {
     private String topologyId;
     private EventExecutor mockExecutor;
     private ScheduledThreadPool mockKeepAlive;
     private ThreadPool mockProcessingExecutor;
     private SchemaResourceManager mockSchemaRepoProvider;
 
-    private CallHomeMountDispatcher instance;
+    private CallHomeMountFactory instance;
     private DataBroker mockDataBroker;
     private DOMMountPointService mockMount;
 
@@ -71,7 +71,7 @@ public class CallHomeMountDispatcherTest {
         mockBuilderFactory = mock(NetconfClientConfigurationBuilderFactory .class);
         mockBaseSchemas = mock(BaseNetconfSchemas.class);
 
-        instance = new CallHomeMountDispatcher(topologyId, mockExecutor, mockKeepAlive,
+        instance = new CallHomeMountFactory(topologyId, mockExecutor, mockKeepAlive,
                 mockProcessingExecutor, mockSchemaRepoProvider, mockBaseSchemas, mockDataBroker, mockMount,
                 mockBuilderFactory) {
             @Override
@@ -115,14 +115,15 @@ public class CallHomeMountDispatcherTest {
     }
 
     @Test
-    public void noSessionIsCreatedWithoutAContextAvailableForAGivenAddress() {
+    public void noSessionIsCreatedWithoutAContextAvailableForAGivenAddress() throws Exception {
         // given
         final InetSocketAddress someAddress = InetSocketAddress.createUnresolved("1.2.3.4", 123);
         final NetconfClientConfiguration someCfg = someConfiguration(someAddress);
         // when
-        final Future<NetconfClientSession> future = instance.createClient(someCfg);
+        final var future = instance.createClient(someCfg);
         // then
-        assertFalse(future.isSuccess());
+        assertNotNull(future);
+        assertThrows(ExecutionException.class, future::get);
     }
 
     @Test
index b101975f916f01b7910d99a0e03dbe4f3582968a..0484dd7c9f1f11ef03113c505c6eea2466e89965 100644 (file)
@@ -23,7 +23,7 @@ import org.opendaylight.mdsal.binding.api.DataTreeModification;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
@@ -58,43 +58,43 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
     @Inject
     @Activate
     public NetconfTopologyImpl(
-            @Reference(target = "(type=netconf-client-dispatcher)") final NetconfClientDispatcher clientDispatcher,
+            @Reference(target = "(type=netconf-client-factory)") final NetconfClientFactory clientFactory,
             @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
             @Reference(target = "(type=global-netconf-ssh-scheduled-executor)")
-            final ScheduledThreadPool keepaliveExecutor,
-            @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingExecutor,
+            final ScheduledThreadPool scheduledThreadPool,
+            @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingThreadPool,
             @Reference final SchemaResourceManager schemaRepositoryProvider, @Reference final DataBroker dataBroker,
             @Reference final DOMMountPointService mountPointService,
             @Reference final AAAEncryptionService encryptionService,
-            @Reference final NetconfClientConfigurationBuilderFactory builderFactory,
+            @Reference(target = "(type=default)") final NetconfClientConfigurationBuilderFactory builderFactory,
             @Reference final RpcProviderService rpcProviderService, @Reference final BaseNetconfSchemas baseSchemas,
             @Reference final DeviceActionFactory deviceActionFactory) {
-        this(NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, clientDispatcher, eventExecutor, keepaliveExecutor,
-            processingExecutor, schemaRepositoryProvider, dataBroker, mountPointService, encryptionService,
+        this(NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, clientFactory, eventExecutor, scheduledThreadPool,
+            processingThreadPool, schemaRepositoryProvider, dataBroker, mountPointService, encryptionService,
             builderFactory, rpcProviderService, baseSchemas, deviceActionFactory);
     }
 
-    public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
-            final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-            final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
+    public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientclientFactory,
+            final EventExecutor eventExecutor, final ScheduledThreadPool scheduledThreadPool,
+            final ThreadPool processingThreadPool, final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory,
             final RpcProviderService rpcProviderService, final BaseNetconfSchemas baseSchemas) {
-        this(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
+        this(topologyId, clientclientFactory, eventExecutor, scheduledThreadPool, processingThreadPool,
             schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, builderFactory,
             rpcProviderService, baseSchemas, null);
     }
 
     @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR",
         justification = "DTCL registration of 'this'")
-    public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
-            final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-            final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
+    public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory,
+            final EventExecutor eventExecutor, final ScheduledThreadPool scheduledThreadPool,
+            final ThreadPool processingThreadPool, final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory,
             final RpcProviderService rpcProviderService, final BaseNetconfSchemas baseSchemas,
             final DeviceActionFactory deviceActionFactory) {
-        super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
+        super(topologyId, clientFactory, eventExecutor, scheduledThreadPool, processingThreadPool,
             schemaRepositoryProvider, dataBroker, mountPointService, builderFactory, deviceActionFactory, baseSchemas);
 
         LOG.debug("Registering datastore listener");
index a786462a42fc09f3913c2398ece402a466666119..0b88185c617971bba4ae67bc959e923b64136eef 100644 (file)
@@ -31,7 +31,7 @@ import org.opendaylight.mdsal.binding.api.WriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemas;
@@ -65,7 +65,7 @@ class NetconfTopologyImplTest {
         InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, TOPOLOGY_KEY).build();
 
     @Mock
-    private NetconfClientDispatcher mockedClientDispatcher;
+    private NetconfClientFactory mockedClientFactory;
     @Mock
     private EventExecutor mockedEventExecutor;
     @Mock
@@ -100,7 +100,7 @@ class NetconfTopologyImplTest {
         doReturn(wtx).when(dataBroker).newWriteOnlyTransaction();
         doReturn(CommitInfo.emptyFluentFuture()).when(wtx).commit();
 
-        topology = new TestingNetconfTopologyImpl(TOPOLOGY_KEY.getTopologyId().getValue(), mockedClientDispatcher,
+        topology = new TestingNetconfTopologyImpl(TOPOLOGY_KEY.getTopologyId().getValue(), mockedClientFactory,
             mockedEventExecutor, mockedKeepaliveExecutor, mockedProcessingExecutor, mockedResourceManager, dataBroker,
             mountPointService, encryptionService, builderFactory, rpcProviderService,
             new DefaultBaseNetconfSchemas(new DefaultYangParserFactory()));
@@ -154,14 +154,14 @@ class NetconfTopologyImplTest {
     }
 
     private static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
-        TestingNetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher,
-                final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-                final ThreadPool processingExecutor, final SchemaResourceManager schemaRepositoryProvider,
+        TestingNetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory,
+                final EventExecutor eventExecutor, final ScheduledThreadPool scheduledThreadPool,
+                final ThreadPool processingThreadPool, final SchemaResourceManager schemaRepositoryProvider,
                 final DataBroker dataBroker, final DOMMountPointService mountPointService,
                 final AAAEncryptionService encryptionService,
                 final NetconfClientConfigurationBuilderFactory builderFactory,
                 final RpcProviderService rpcProviderService, final BaseNetconfSchemas baseSchemas) {
-            super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
+            super(topologyId, clientFactory, eventExecutor, scheduledThreadPool, processingThreadPool,
                 schemaRepositoryProvider, dataBroker, mountPointService, encryptionService, builderFactory,
                 rpcProviderService, baseSchemas);
         }
index 19f360030d031ad45b18f359fe464c65246e7f4d..dd6a607a583ffe03708125299b73d30ca85ed6a5 100644 (file)
@@ -141,7 +141,7 @@ final class NetconfNodeContext implements AutoCloseable {
         // Instantiate the handler ...
         masterSalFacade = createSalFacade(netconfNode.requireLockDatastore());
 
-        nodeHandler = new NetconfNodeHandler(setup.getNetconfClientDispatcher(), setup.getEventExecutor(),
+        nodeHandler = new NetconfNodeHandler(setup.getNetconfClientFactory(),
             setup.getKeepaliveExecutor(), setup.getBaseSchemas(), schemaManager, setup.getProcessingExecutor(),
             builderFactory, deviceActionFactory, masterSalFacade, remoteDeviceId, configNode.getNodeId(), netconfNode,
             nodeOptional);
index d80b6f7ec545655cd26023fd98c4e78973f54260..d85e280692945039bf27c1df9dc46a83db7a795f 100644 (file)
@@ -42,7 +42,7 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
@@ -103,7 +103,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
     private final Executor processingExecutor;
     private final ActorSystem actorSystem;
     private final EventExecutor eventExecutor;
-    private final NetconfClientDispatcher clientDispatcher;
+    private final NetconfClientFactory clientFactory;
     private final String topologyId;
     private final Duration writeTxIdleTimeout;
     private final DOMMountPointService mountPointService;
@@ -123,7 +123,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
             @Reference(target = "(type=global-netconf-processing-executor)") final ThreadPool processingExecutor,
             @Reference final ActorSystemProvider actorSystemProvider,
             @Reference(target = "(type=global-event-executor)") final EventExecutor eventExecutor,
-            @Reference(target = "(type=netconf-client-dispatcher)") final NetconfClientDispatcher clientDispatcher,
+            @Reference(target = "(type=netconf-client-factory)") final NetconfClientFactory clientFactory,
             @Reference final DOMMountPointService mountPointService,
             @Reference final AAAEncryptionService encryptionService,
             @Reference final RpcProviderService rpcProviderService,
@@ -132,7 +132,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
             @Reference final NetconfClientConfigurationBuilderFactory builderFactory,
             final Configuration configuration) {
         this(baseSchemas, dataBroker, clusterSingletonServiceProvider, keepaliveExecutor.getExecutor(),
-            processingExecutor.getExecutor(), actorSystemProvider.getActorSystem(), eventExecutor, clientDispatcher,
+            processingExecutor.getExecutor(), actorSystemProvider.getActorSystem(), eventExecutor, clientFactory,
             mountPointService, encryptionService, rpcProviderService, deviceActionFactory, resourceManager,
             builderFactory, configuration.topology$_$id(),
             Uint16.valueOf(configuration.write$_$transaction$_$idle$_$timeout()));
@@ -143,12 +143,12 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
             final ClusterSingletonServiceProvider clusterSingletonServiceProvider,
             final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor,
             final ActorSystemProvider actorSystemProvider, final EventExecutor eventExecutor,
-            final NetconfClientDispatcher clientDispatcher, final DOMMountPointService mountPointService,
+            final NetconfClientFactory clientFactory, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
             final DeviceActionFactory deviceActionFactory, final SchemaResourceManager resourceManager,
             final NetconfClientConfigurationBuilderFactory builderFactory) {
         this(baseSchemas, dataBroker, clusterSingletonServiceProvider, keepaliveExecutor.getExecutor(),
-            processingExecutor.getExecutor(), actorSystemProvider.getActorSystem(), eventExecutor, clientDispatcher,
+            processingExecutor.getExecutor(), actorSystemProvider.getActorSystem(), eventExecutor, clientFactory,
             mountPointService, encryptionService, rpcProviderService, deviceActionFactory, resourceManager,
             builderFactory, NetconfNodeUtils.DEFAULT_TOPOLOGY_NAME, Uint16.ZERO);
     }
@@ -159,7 +159,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
             final ClusterSingletonServiceProvider clusterSingletonServiceProvider,
             final ScheduledExecutorService keepaliveExecutor, final Executor processingExecutor,
             final ActorSystem actorSystem, final EventExecutor eventExecutor,
-            final NetconfClientDispatcher clientDispatcher, final DOMMountPointService mountPointService,
+            final NetconfClientFactory clientFactory, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
             final DeviceActionFactory deviceActionFactory, final SchemaResourceManager resourceManager,
             final NetconfClientConfigurationBuilderFactory builderFactory, final String topologyId,
@@ -171,7 +171,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
         this.processingExecutor = requireNonNull(processingExecutor);
         this.actorSystem = requireNonNull(actorSystem);
         this.eventExecutor = requireNonNull(eventExecutor);
-        this.clientDispatcher = requireNonNull(clientDispatcher);
+        this.clientFactory = requireNonNull(clientFactory);
         this.topologyId = requireNonNull(topologyId);
         writeTxIdleTimeout = Duration.ofSeconds(writeTransactionIdleTimeout.toJava());
         this.mountPointService = mountPointService;
@@ -341,7 +341,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
                 .setKeepaliveExecutor(keepaliveExecutor)
                 .setProcessingExecutor(processingExecutor)
                 .setTopologyId(topologyId)
-                .setNetconfClientDispatcher(clientDispatcher)
+                .setNetconfClientFactory(clientFactory)
                 .setSchemaResourceDTO(resourceManager.getSchemaResources(netconfNode.getSchemaCacheDirectory(),
                     deviceId))
                 .setIdleTimeout(writeTxIdleTimeout)
index 1aaf469af9fd604ea448d19093d4c155993a8ac1..6ac1722993b36c074e02a3252a436830ebc5d591 100644 (file)
@@ -16,7 +16,7 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.NetconfDevice;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -31,7 +31,7 @@ public class NetconfTopologySetup {
     private final Executor processingExecutor;
     private final ActorSystem actorSystem;
     private final EventExecutor eventExecutor;
-    private final NetconfClientDispatcher netconfClientDispatcher;
+    private final NetconfClientFactory netconfClientFactory;
     private final String topologyId;
     private final NetconfDevice.SchemaResourcesDTO schemaResourceDTO;
     private final Duration idleTimeout;
@@ -46,7 +46,7 @@ public class NetconfTopologySetup {
         processingExecutor = builder.getProcessingExecutor();
         actorSystem = builder.getActorSystem();
         eventExecutor = builder.getEventExecutor();
-        netconfClientDispatcher = builder.getNetconfClientDispatcher();
+        netconfClientFactory = builder.getNetconfClientFactory();
         topologyId = builder.getTopologyId();
         schemaResourceDTO = builder.getSchemaResourceDTO();
         idleTimeout = builder.getIdleTimeout();
@@ -89,8 +89,8 @@ public class NetconfTopologySetup {
         return topologyId;
     }
 
-    public NetconfClientDispatcher getNetconfClientDispatcher() {
-        return netconfClientDispatcher;
+    public NetconfClientFactory getNetconfClientFactory() {
+        return netconfClientFactory;
     }
 
     public NetconfDevice.SchemaResourcesDTO getSchemaResourcesDTO() {
@@ -115,7 +115,7 @@ public class NetconfTopologySetup {
         private ActorSystem actorSystem;
         private EventExecutor eventExecutor;
         private String topologyId;
-        private NetconfClientDispatcher netconfClientDispatcher;
+        private NetconfClientFactory netconfClientFactory;
         private NetconfDevice.SchemaResourcesDTO schemaResourceDTO;
         private Duration idleTimeout;
         private BaseNetconfSchemas baseSchemas;
@@ -219,12 +219,12 @@ public class NetconfTopologySetup {
             return this;
         }
 
-        NetconfClientDispatcher getNetconfClientDispatcher() {
-            return netconfClientDispatcher;
+        NetconfClientFactory getNetconfClientFactory() {
+            return netconfClientFactory;
         }
 
-        public NetconfTopologySetupBuilder setNetconfClientDispatcher(final NetconfClientDispatcher clientDispatcher) {
-            netconfClientDispatcher = clientDispatcher;
+        public NetconfTopologySetupBuilder setNetconfClientFactory(final NetconfClientFactory clientFactory) {
+            netconfClientFactory = clientFactory;
             return this;
         }
 
index a5cee5177a9f50327d4f637e8916fee7a21758e9..477f85bde951957363d1e1adb0d408aa06d17ddf 100644 (file)
@@ -34,7 +34,6 @@ import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 import com.typesafe.config.ConfigFactory;
 import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.File;
 import java.util.Iterator;
@@ -93,7 +92,7 @@ import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegist
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.mdsal.singleton.dom.impl.DOMClusterSingletonServiceProviderImpl;
 import org.opendaylight.netconf.api.CapabilityURN;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
@@ -186,7 +185,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
 
     @Mock private RpcProviderService mockRpcProviderService;
     @Mock private Registration mockRpcReg;
-    @Mock private NetconfClientDispatcher mockClientDispatcher;
+    @Mock private NetconfClientFactory mockClientFactory;
     @Mock private AAAEncryptionService mockEncryptionService;
     @Mock private ScheduledExecutorService mockKeepaliveExecutor;
     @Mock private DeviceActionFactory deviceActionFactory;
@@ -271,7 +270,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
         setupSlave();
 
         yangNodeInstanceId = bindingToNormalized.toYangInstanceIdentifier(NODE_INSTANCE_ID);
-        doReturn(mock(Future.class)).when(mockClientDispatcher).createClient(any());
+        doReturn(mock(ListenableFuture.class)).when(mockClientFactory).createClient(any());
 
         LOG.info("****** Setup complete");
     }
@@ -308,7 +307,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
 
         masterNetconfTopologyManager = new NetconfTopologyManager(BASE_SCHEMAS, masterDataBroker,
                 masterClusterSingletonServiceProvider, mockKeepaliveExecutor, MoreExecutors.directExecutor(),
-                masterSystem, eventExecutor, mockClientDispatcher, masterMountPointService,
+                masterSystem, eventExecutor, mockClientFactory, masterMountPointService,
                 mockEncryptionService, mockRpcProviderService, deviceActionFactory, resourceManager, builderFactory,
                 TOPOLOGY_ID, Uint16.ZERO) {
             @Override
@@ -345,7 +344,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
 
         slaveNetconfTopologyManager = new NetconfTopologyManager(BASE_SCHEMAS, slaveDataBroker,
                 mockSlaveClusterSingletonServiceProvider, mockKeepaliveExecutor, MoreExecutors.directExecutor(),
-                slaveSystem, eventExecutor, mockClientDispatcher, slaveMountPointService,
+                slaveSystem, eventExecutor, mockClientFactory, slaveMountPointService,
                 mockEncryptionService, mockRpcProviderService, deviceActionFactory, resourceManager, builderFactory,
                 TOPOLOGY_ID, Uint16.ZERO) {
             @Override
index 3827787b3c1ceea4487ebd0e5a05a46f875c1ac2..97e2f947f01cae1e9c9db25b27eea1471bf23b13 100644 (file)
@@ -55,7 +55,7 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration;
 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.impl.DefaultSchemaResourceManager;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
@@ -114,7 +114,7 @@ public class NetconfTopologyManagerTest extends AbstractBaseSchemasTest {
         final ExecutorService processingService = mock(ExecutorService.class);
         final ActorSystem actorSystem = mock(ActorSystem.class);
         final EventExecutor eventExecutor = mock(EventExecutor.class);
-        final NetconfClientDispatcher clientDispatcher = mock(NetconfClientDispatcher.class);
+        final NetconfClientFactory clientFactory = mock(NetconfClientFactory.class);
         final DOMMountPointService mountPointService = mock(DOMMountPointService.class);
         final AAAEncryptionService encryptionService = mock(AAAEncryptionService.class);
         final DeviceActionFactory deviceActionFactory = mock(DeviceActionFactory.class);
@@ -127,7 +127,7 @@ public class NetconfTopologyManagerTest extends AbstractBaseSchemasTest {
         doReturn(mockRpcReg).when(rpcProviderService).registerRpcImplementations(any());
 
         netconfTopologyManager = new NetconfTopologyManager(BASE_SCHEMAS, dataBroker, clusterSingletonServiceProvider,
-                keepaliveExecutor, processingService, actorSystem, eventExecutor, clientDispatcher,
+                keepaliveExecutor, processingService, actorSystem, eventExecutor, clientFactory,
                 mountPointService, encryptionService, rpcProviderService, deviceActionFactory,
                 new DefaultSchemaResourceManager(new DefaultYangParserFactory()), builderFactory,
                 TOPOLOGY_ID, Uint16.ZERO) {
index b7bcc26313e8cac7c7810954210c4ec4f5024b6c..c61f0fe7002ed29368028ed35090e6c170e53daa 100644 (file)
@@ -21,7 +21,7 @@ import org.opendaylight.controller.config.threadpool.ThreadPool;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
@@ -44,29 +44,30 @@ public abstract class AbstractNetconfTopology {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
 
     private final HashMap<NodeId, NetconfNodeHandler> activeConnectors = new HashMap<>();
-    private final NetconfClientDispatcher clientDispatcher;
+    private final NetconfClientFactory clientFactory;
     private final EventExecutor eventExecutor;
     private final DeviceActionFactory deviceActionFactory;
     private final SchemaResourceManager schemaManager;
     private final BaseNetconfSchemas baseSchemas;
     private final NetconfClientConfigurationBuilderFactory builderFactory;
 
-    protected final ScheduledExecutorService keepaliveExecutor;
+    protected final ScheduledExecutorService scheduledExecutor;
     protected final Executor processingExecutor;
     protected final DataBroker dataBroker;
     protected final DOMMountPointService mountPointService;
     protected final String topologyId;
 
-    protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
-            final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
-            final ThreadPool processingExecutor, final SchemaResourceManager schemaManager, final DataBroker dataBroker,
-            final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory,
+    protected AbstractNetconfTopology(final String topologyId, final NetconfClientFactory clientDispatcher,
+            final EventExecutor eventExecutor, final ScheduledThreadPool scheduledThreadPool,
+            final ThreadPool processingThreadPool, final SchemaResourceManager schemaManager,
+            final DataBroker dataBroker, final DOMMountPointService mountPointService,
+            final NetconfClientConfigurationBuilderFactory builderFactory,
             final DeviceActionFactory deviceActionFactory, final BaseNetconfSchemas baseSchemas) {
         this.topologyId = requireNonNull(topologyId);
-        this.clientDispatcher = clientDispatcher;
+        this.clientFactory = clientDispatcher;
         this.eventExecutor = eventExecutor;
-        this.keepaliveExecutor = keepaliveExecutor.getExecutor();
-        this.processingExecutor = processingExecutor.getExecutor();
+        this.scheduledExecutor = scheduledThreadPool.getExecutor();
+        this.processingExecutor = processingThreadPool.getExecutor();
         this.schemaManager = requireNonNull(schemaManager);
         this.deviceActionFactory = deviceActionFactory;
         this.dataBroker = requireNonNull(dataBroker);
@@ -124,9 +125,9 @@ public abstract class AbstractNetconfTopology {
 
         final NetconfNodeHandler nodeHandler;
         try {
-            nodeHandler = new NetconfNodeHandler(clientDispatcher, eventExecutor, keepaliveExecutor, baseSchemas,
-                schemaManager, processingExecutor, builderFactory, deviceActionFactory, deviceSalFacade, deviceId,
-                nodeId, netconfNode, nodeOptional);
+            nodeHandler = new NetconfNodeHandler(clientFactory, scheduledExecutor, baseSchemas,
+                schemaManager, processingExecutor, builderFactory, deviceActionFactory, deviceSalFacade,
+                deviceId, nodeId, netconfNode, nodeOptional);
         } catch (IllegalArgumentException e) {
             // This is a workaround for NETCONF-1114 where the encrypted password's lexical structure is not enforced
             // in the datastore and it ends up surfacing when we decrypt the password.
index edf74fc3d5ebe5927371e911f94b94bff94aac22..9ebaa1a5a0aee50d896ac994f28125f2d584e223 100644 (file)
@@ -33,10 +33,14 @@ import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 
 /**
- * Default implementation of NetconfClientConfigurationBuildFactory.
+ * Legacy implementation of NetconfClientConfigurationBuildFactory.
+ *
+ * @deprecated as outdated. Should be replaced with {@link NetconfClientConfigurationBuilderFactoryImpl} once
+ *     callhome-provider is migrated to transport-api.
  */
-@Component
+@Component(service = NetconfClientConfigurationBuilderFactory.class, property = "type=legacy")
 @Singleton
+@Deprecated(forRemoval = true)
 public final class DefaultNetconfClientConfigurationBuilderFactory implements NetconfClientConfigurationBuilderFactory {
     private final SslHandlerFactoryProvider sslHandlerFactoryProvider;
     private final AAAEncryptionService encryptionService;
diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImpl.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImpl.java
new file mode 100644 (file)
index 0000000..72ff522
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.netconf.topology.spi;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.io.StringReader;
+import java.security.KeyPair;
+import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.aaa.encrypt.PKIUtil;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
+import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
+import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
+import org.opendaylight.netconf.shaded.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
+import org.opendaylight.netconf.shaded.sshd.common.keyprovider.KeyIdentityProvider;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev230417.password.grouping.password.type.CleartextPasswordBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.client.rev230417.netconf.client.initiate.stack.grouping.transport.ssh.ssh.SshClientParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.client.rev230417.netconf.client.initiate.stack.grouping.transport.ssh.ssh.TcpClientParametersBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.ssh.client.grouping.ClientIdentity;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.ssh.client.grouping.ClientIdentityBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ssh.client.rev230417.ssh.client.grouping.client.identity.PasswordBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.connection.parameters.Protocol.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.Credentials;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.credentials.KeyAuth;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.credentials.LoginPw;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.credentials.LoginPwUnencrypted;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * Default implementation of NetconfClientConfigurationBuildFactory.
+ */
+@Component(service = NetconfClientConfigurationBuilderFactory.class, property = "type=default")
+@Singleton
+public final class NetconfClientConfigurationBuilderFactoryImpl implements NetconfClientConfigurationBuilderFactory {
+    private final SslHandlerFactoryProvider sslHandlerFactoryProvider;
+    private final AAAEncryptionService encryptionService;
+    private final CredentialProvider credentialProvider;
+
+    @Inject
+    @Activate
+    public NetconfClientConfigurationBuilderFactoryImpl(
+        @Reference final AAAEncryptionService encryptionService,
+        @Reference final CredentialProvider credentialProvider,
+        @Reference final SslHandlerFactoryProvider sslHandlerFactoryProvider) {
+        this.encryptionService = requireNonNull(encryptionService);
+        this.credentialProvider = requireNonNull(credentialProvider);
+        this.sslHandlerFactoryProvider = requireNonNull(sslHandlerFactoryProvider);
+    }
+
+    @Override
+    public NetconfClientConfigurationBuilder createClientConfigurationBuilder(final NodeId nodeId,
+        final NetconfNode node) {
+        final var builder = NetconfClientConfigurationBuilder.create();
+        final var protocol = node.getProtocol();
+        if (node.requireTcpOnly()) {
+            builder.withProtocol(NetconfClientProtocol.TCP);
+        } else if (protocol == null || protocol.getName() == Name.SSH) {
+            builder.withProtocol(NetconfClientProtocol.SSH);
+            setSshParametersFromCredentials(builder, node.getCredentials());
+        } else if (protocol.getName() == Name.TLS) {
+            builder.withProtocol(NetconfClientProtocol.TLS).withTransportSslHandlerFactory(channel -> {
+                final var sslHandlerBuilder =
+                    sslHandlerFactoryProvider.getSslHandlerFactory(protocol.getSpecification());
+                return sslHandlerBuilder.createSslHandler();
+            });
+        } else {
+            throw new IllegalArgumentException("Unsupported protocol type: " + protocol.getName());
+        }
+
+        final var helloCapabilities = node.getOdlHelloMessageCapabilities();
+        if (helloCapabilities != null) {
+            builder.withOdlHelloCapabilities(List.copyOf(helloCapabilities.requireCapability()));
+        }
+
+        return builder
+            .withName(nodeId.getValue())
+            .withTcpParameters(new TcpClientParametersBuilder()
+                .setRemoteAddress(node.requireHost())
+                .setRemotePort(node.requirePort()).build())
+            .withConnectionTimeoutMillis(node.requireConnectionTimeoutMillis().toJava());
+    }
+
+    private void setSshParametersFromCredentials(final NetconfClientConfigurationBuilder confBuilder,
+        final Credentials credentials) {
+        final var sshParamsBuilder = new SshClientParametersBuilder();
+        if (credentials instanceof LoginPwUnencrypted unencrypted) {
+            final var loginPassword = unencrypted.getLoginPasswordUnencrypted();
+            sshParamsBuilder.setClientIdentity(loginPasswordIdentity(
+                loginPassword.getUsername(), loginPassword.getPassword()));
+
+        } else if (credentials instanceof LoginPw loginPw) {
+            final var loginPassword = loginPw.getLoginPassword();
+            sshParamsBuilder.setClientIdentity(loginPasswordIdentity(
+                loginPassword.getUsername(), encryptionService.decrypt(loginPassword.getPassword())));
+
+        } else if (credentials instanceof KeyAuth keyAuth) {
+            final var keyBased = keyAuth.getKeyBased();
+            sshParamsBuilder.setClientIdentity(new ClientIdentityBuilder().setUsername(keyBased.getUsername()).build());
+            confBuilder.withSshConfigurator(factoryMgr -> {
+                final var keyPair = getKeyPair(keyBased.getKeyId(), credentialProvider, encryptionService);
+                factoryMgr.setKeyIdentityProvider(KeyIdentityProvider.wrapKeyPairs(keyPair));
+                final var factory = new UserAuthPublicKeyFactory();
+                factory.setSignatureFactories(factoryMgr.getSignatureFactories());
+                factoryMgr.setUserAuthFactories(List.of(factory));
+            });
+        } else {
+            throw new IllegalArgumentException("Unsupported credential type: " + credentials.getClass());
+        }
+        confBuilder.withSshParameters(sshParamsBuilder.build());
+    }
+
+    private static ClientIdentity loginPasswordIdentity(final String username, final String password) {
+        requireNonNull(username, "username is undefined");
+        requireNonNull(password, "password is undefined");
+        return new ClientIdentityBuilder()
+            .setUsername(username)
+            .setPassword(new PasswordBuilder()
+                .setPasswordType(new CleartextPasswordBuilder().setCleartextPassword(password).build())
+                .build())
+            .build();
+    }
+
+    private static KeyPair getKeyPair(final String keyId,
+        final CredentialProvider credentialProvider, final AAAEncryptionService encryptionService) {
+
+        // public key retrieval logic taken from DatastoreBackedPublicKeyAuth
+        final var dsKeypair = credentialProvider.credentialForId(keyId);
+        if (dsKeypair == null) {
+            throw new IllegalArgumentException("No keypair found with keyId=" + keyId);
+        }
+        final var passPhrase = Strings.isNullOrEmpty(dsKeypair.getPassphrase()) ? "" : dsKeypair.getPassphrase();
+        try {
+            return new PKIUtil().decodePrivateKey(
+                new StringReader(encryptionService.decrypt(dsKeypair.getPrivateKey()).replace("\\n", "\n")),
+                encryptionService.decrypt(passPhrase));
+        } catch (IOException e) {
+            throw new IllegalStateException("Could not decode private key with keyId=" + keyId, e);
+        }
+    }
+}
index 47f980c66039ce8fa1c47e8e1077254aab9e1039..2e0de08a1c6e4f817522865ce51f2b56cf2d0194 100644 (file)
@@ -10,11 +10,12 @@ package org.opendaylight.netconf.topology.spi;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningScheduledExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -22,7 +23,7 @@ import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.checkerframework.checker.lock.qual.Holding;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.dom.api.DOMNotification;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.mdsal.LibraryModulesSchemas;
 import org.opendaylight.netconf.client.mdsal.LibrarySchemaSourceProvider;
@@ -40,6 +41,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.spi.KeepaliveSalFacade;
+import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
@@ -58,11 +60,11 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
     private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeHandler.class);
 
     private final @NonNull List<SchemaSourceRegistration<?>> yanglibRegistrations;
-    private final @NonNull NetconfClientDispatcher clientDispatcher;
+    private final @NonNull NetconfClientFactory clientFactory;
     private final @NonNull NetconfClientConfiguration clientConfig;
     private final @NonNull NetconfDeviceCommunicator communicator;
     private final @NonNull RemoteDeviceHandler delegate;
-    private final @NonNull EventExecutor eventExecutor;
+    private final @NonNull ListeningScheduledExecutorService scheduledExecutor;
     private final @NonNull RemoteDeviceId deviceId;
 
     private final long maxAttempts;
@@ -74,17 +76,18 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
     @GuardedBy("this")
     private long lastSleep;
     @GuardedBy("this")
-    private Future<?> currentTask;
+    private ListenableFuture<?> currentTask;
 
-    public NetconfNodeHandler(final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor,
-            final ScheduledExecutorService keepaliveExecutor, final BaseNetconfSchemas baseSchemas,
+    public NetconfNodeHandler(final NetconfClientFactory clientFactory,
+            final ScheduledExecutorService scheduledExecutor, final BaseNetconfSchemas baseSchemas,
             final SchemaResourceManager schemaManager, final Executor processingExecutor,
             final NetconfClientConfigurationBuilderFactory builderFactory,
             final DeviceActionFactory deviceActionFactory, final RemoteDeviceHandler delegate,
             final RemoteDeviceId deviceId, final NodeId nodeId, final NetconfNode node,
             final NetconfNodeAugmentedOptional nodeOptional) {
-        this.clientDispatcher = requireNonNull(clientDispatcher);
-        this.eventExecutor = requireNonNull(eventExecutor);
+        this.clientFactory = requireNonNull(clientFactory);
+        // FIXME: do not wrap this executor
+        this.scheduledExecutor = MoreExecutors.listeningDecorator(scheduledExecutor);
         this.delegate = requireNonNull(delegate);
         this.deviceId = requireNonNull(deviceId);
 
@@ -104,7 +107,7 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
         final long keepaliveDelay = node.requireKeepaliveDelay().toJava();
         if (keepaliveDelay > 0) {
             LOG.info("Adding keepalive facade, for device {}", nodeId);
-            salFacade = keepAliveFacade = new KeepaliveSalFacade(deviceId, this, keepaliveExecutor, keepaliveDelay,
+            salFacade = keepAliveFacade = new KeepaliveSalFacade(deviceId, this, scheduledExecutor, keepaliveDelay,
                 node.requireDefaultRequestTimeoutMillis().toJava());
         } else {
             salFacade = this;
@@ -154,11 +157,16 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
 
     @Holding("this")
     private void lockedConnect() {
-        currentTask = clientDispatcher.createClient(clientConfig);
-        currentTask.addListener(this::connectComplete);
+        try {
+            final var clientFuture = clientFactory.createClient(clientConfig);
+            clientFuture.addListener(() -> connectComplete(clientFuture), MoreExecutors.directExecutor());
+            currentTask = clientFuture;
+        } catch (UnsupportedConfigurationException e) {
+            onDeviceFailed(e);
+        }
     }
 
-    private void connectComplete(final Future<?> future) {
+    private void connectComplete(final ListenableFuture<?> future) {
         // Locked manipulation of internal state
         synchronized (this) {
             // A quick sanity check
@@ -166,16 +174,18 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
                 LOG.warn("Ignoring connection completion, expected {} actual {}", future, currentTask);
                 return;
             }
-
             currentTask = null;
-            final var cause = future.cause();
-            if (cause == null || cause instanceof CancellationException) {
-                // Success or cancellation, nothing else to do.
-                // In case of success the rest of the setup is driven by RemoteDeviceHandler callbacks
-                return;
+            // ListenableFuture provide no detail on error unless you attempt to get() the result
+            // then only the original exception is rethrown wrapped with ExecutionException
+            try {
+                if (future.isCancelled() || future.isDone() && future.get() != null) {
+                    // Success or cancellation, nothing else to do.
+                    // In case of success the rest of the setup is driven by RemoteDeviceHandler callbacks
+                    return;
+                }
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.debug("Connection attempt {} to {} failed", attempts, deviceId, e);
             }
-
-            LOG.debug("Connection attempt {} to {} failed", attempts, deviceId, cause);
         }
 
         // We are invoking callbacks, do not hold locks
@@ -257,9 +267,9 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
 
         // Schedule a task for the right time. We always go through the executor to eliminate the special case of
         // immediate reconnect. While we could check and got to lockedConnect(), it makes for a rare special case.
-        // That special case makes for more code paths to test and introduces additional uncertainty as to whether
-        // the attempt was executed on on this thread or not.
-        currentTask = eventExecutor.schedule(this::reconnect, delayMillis, TimeUnit.MILLISECONDS);
+        // That special case makes for more code paths to test and introduces additional uncertainty whether
+        // the attempt was executed on this thread or not.
+        currentTask = scheduledExecutor.schedule(this::reconnect, delayMillis, TimeUnit.MILLISECONDS);
         return null;
     }
 
diff --git a/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImplTest.java b/apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfClientConfigurationBuilderFactoryImplTest.java
new file mode 100644 (file)
index 0000000..2daec7d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.netconf.topology.spi;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.NoSuchElementException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.aaa.encrypt.AAAEncryptionService;
+import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
+import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
+import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.connection.parameters.Protocol.Name;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.connection.parameters.ProtocolBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.credentials.LoginPwUnencryptedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev231025.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencryptedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev221225.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.common.Decimal64;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+
+@ExtendWith(MockitoExtension.class)
+class NetconfClientConfigurationBuilderFactoryImplTest {
+    private static final NodeId NODE_ID = new NodeId("testing-node");
+    private static final Host HOST = new Host(new IpAddress(new Ipv4Address("127.0.0.1")));
+    private static final PortNumber PORT = new PortNumber(Uint16.valueOf(9999));
+
+    @Mock
+    private NetconfClientSessionListener sessionListener;
+    @Mock
+    private AAAEncryptionService encryptionService;
+    @Mock
+    private CredentialProvider credentialProvider;
+    @Mock
+    private SslHandlerFactoryProvider sslHandlerFactoryProvider;
+
+    private NetconfNodeBuilder nodeBuilder;
+    private NetconfClientConfigurationBuilderFactoryImpl factory;
+
+    @BeforeEach
+    void beforeEach() {
+        nodeBuilder = new NetconfNodeBuilder()
+            .setHost(HOST).setPort(PORT)
+            .setReconnectOnChangedSchema(true)
+            .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
+            .setBetweenAttemptsTimeoutMillis(Uint16.valueOf(100))
+            .setKeepaliveDelay(Uint32.valueOf(1000))
+            .setCredentials(new LoginPwUnencryptedBuilder()
+                .setLoginPasswordUnencrypted(new LoginPasswordUnencryptedBuilder()
+                    .setUsername("test-user")
+                    .setPassword("test-password")
+                    .build())
+                .build())
+            .setMaxConnectionAttempts(Uint32.ZERO)
+            .setSleepFactor(Decimal64.valueOf("1.5"))
+            .setConnectionTimeoutMillis(Uint32.valueOf(20000));
+        factory = new NetconfClientConfigurationBuilderFactoryImpl(encryptionService, credentialProvider,
+            sslHandlerFactoryProvider);
+    }
+
+    private void assertConfig(NetconfClientConfiguration config) {
+        assertNotNull(config);
+        assertNotNull(config.getTcpParameters());
+        assertEquals(HOST, config.getTcpParameters().getRemoteAddress());
+        assertEquals(PORT, config.getTcpParameters().getRemotePort());
+        assertSame(sessionListener, config.getSessionListener());
+    }
+
+    @Test
+    void testDefault() {
+        final var config = createConfig(nodeBuilder.setTcpOnly(false).build());
+        assertConfig(config);
+        assertEquals(NetconfClientProtocol.SSH, config.getProtocol());
+        assertNotNull(config.getSshParameters());
+    }
+
+    @Test
+    void testSsh() {
+        final var config = createConfig(
+            nodeBuilder.setTcpOnly(false).setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build());
+        assertConfig(config);
+        assertEquals(NetconfClientProtocol.SSH, config.getProtocol());
+        assertNotNull(config.getSshParameters());
+    }
+
+    @Test
+    void testTcp() {
+        final var config = createConfig(nodeBuilder.setTcpOnly(true).build());
+        assertConfig(config);
+        assertEquals(NetconfClientProtocol.TCP, config.getProtocol());
+    }
+
+    @Test
+    void testTls() {
+        final var config = createConfig(
+            nodeBuilder.setTcpOnly(false).setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build());
+        assertConfig(config);
+        assertEquals(NetconfClientProtocol.TLS, config.getProtocol());
+        assertNotNull(config.getTransportSslHandlerFactory());
+    }
+
+    @Test
+    void noPort() {
+        assertThrows(NoSuchElementException.class, () -> createConfig(nodeBuilder.setPort(null).build()));
+    }
+
+    @Test
+    void noHost() {
+        assertThrows(NoSuchElementException.class, () -> createConfig(nodeBuilder.setHost(null).build()));
+    }
+
+    private NetconfClientConfiguration createConfig(final NetconfNode netconfNode) {
+        return factory.createClientConfigurationBuilder(NODE_ID, netconfNode)
+            .withSessionListener(sessionListener)
+            .build();
+    }
+}
index 3742b1c84800f257a65d75f9bbdfbd8de579950b..7a5bc3b19081af2385441def126769a741a3f43c 100644 (file)
@@ -11,6 +11,7 @@ import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -20,15 +21,13 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 
 import com.google.common.net.InetAddresses;
-import io.netty.util.concurrent.DefaultPromise;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.ImmediateEventExecutor;
-import io.netty.util.concurrent.ScheduledFuture;
-import io.netty.util.concurrent.SucceededFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.SettableFuture;
 import java.net.InetSocketAddress;
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -40,7 +39,7 @@ import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.netconf.api.CapabilityURN;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
@@ -80,7 +79,7 @@ public class NetconfNodeHandlerTest {
 
     // Core setup
     @Mock
-    private ScheduledExecutorService keepaliveExecutor;
+    private ScheduledExecutorService scheduledExecutor;
     @Mock
     private SchemaResourceManager schemaManager;
     @Mock
@@ -100,7 +99,7 @@ public class NetconfNodeHandlerTest {
 
     // Mock client dispatcher-related things
     @Mock
-    private NetconfClientDispatcher clientDispatcher;
+    private NetconfClientFactory clientFactory;
     @Mock
     private NetconfClientSession clientSession;
     @Captor
@@ -112,8 +111,6 @@ public class NetconfNodeHandlerTest {
 
     // Mock eventExecutor-related things
     @Mock
-    private EventExecutor eventExecutor;
-    @Mock
     private ScheduledFuture<?> scheduleFuture;
     @Captor
     private ArgumentCaptor<Runnable> scheduleCaptor;
@@ -135,7 +132,7 @@ public class NetconfNodeHandlerTest {
     @Before
     public void before() {
         // Instantiate the handler
-        handler = new NetconfNodeHandler(clientDispatcher, eventExecutor, keepaliveExecutor, BASE_SCHEMAS,
+        handler = new NetconfNodeHandler(clientFactory, scheduledExecutor, BASE_SCHEMAS,
             schemaManager, processingExecutor,
             new DefaultNetconfClientConfigurationBuilderFactory(encryptionService, credentialProvider,
                 sslHandlerFactoryProvider),
@@ -163,7 +160,7 @@ public class NetconfNodeHandlerTest {
     }
 
     @Test
-    public void successfullOnDeviceConnectedPropagates() {
+    public void successfulOnDeviceConnectedPropagates() throws Exception {
         assertSuccessfulConnect();
         assertEquals(1, handler.attempts());
 
@@ -184,31 +181,32 @@ public class NetconfNodeHandlerTest {
     }
 
     @Test
-    public void failedSchemaCausesReconnect() {
+    public void failedSchemaCausesReconnect() throws Exception {
         assertSuccessfulConnect();
         assertEquals(1, handler.attempts());
 
         // Note: this will count as a second attempt
-        doReturn(scheduleFuture).when(eventExecutor).schedule(scheduleCaptor.capture(), eq(150L),
-            eq(TimeUnit.MILLISECONDS));
+        doReturn(scheduleFuture).when(scheduledExecutor)
+            .schedule(scheduleCaptor.capture(), anyLong(), any(TimeUnit.class));
+
         handler.onDeviceFailed(new AssertionError("schema failure"));
 
         assertEquals(2, handler.attempts());
 
         // and when we run the task, we get a clientDispatcher invocation, but attempts are still the same
         scheduleCaptor.getValue().run();
-        verify(clientDispatcher, times(2)).createClient(any());
+        verify(clientFactory, times(2)).createClient(any());
         assertEquals(2, handler.attempts());
     }
 
     @Test
-    public void downAfterUpCausesReconnect() {
+    public void downAfterUpCausesReconnect() throws Exception {
         // Let's borrow common bits
-        successfullOnDeviceConnectedPropagates();
+        successfulOnDeviceConnectedPropagates();
 
         // when the device is connected, we propagate the information and initiate reconnect
         doNothing().when(delegate).onDeviceDisconnected();
-        doReturn(scheduleFuture).when(eventExecutor).schedule(scheduleCaptor.capture(), eq(100L),
+        doReturn(scheduleFuture).when(scheduledExecutor).schedule(scheduleCaptor.capture(), eq(100L),
             eq(TimeUnit.MILLISECONDS));
         handler.onDeviceDisconnected();
 
@@ -216,46 +214,45 @@ public class NetconfNodeHandlerTest {
 
         // and when we run the task, we get a clientDispatcher invocation, but attempts are still the same
         scheduleCaptor.getValue().run();
-        verify(clientDispatcher, times(2)).createClient(any());
+        verify(clientFactory, times(2)).createClient(any());
         assertEquals(1, handler.attempts());
     }
 
     @Test
-    public void socketFailuresAreRetried() {
-        final var firstPromise = new DefaultPromise<NetconfClientSession>(ImmediateEventExecutor.INSTANCE);
-        final var secondPromise = new DefaultPromise<NetconfClientSession>(ImmediateEventExecutor.INSTANCE);
-        doReturn(firstPromise, secondPromise).when(clientDispatcher).createClient(any());
+    public void socketFailuresAreRetried() throws Exception {
+        final var firstFuture = SettableFuture.create();
+        final var secondFuture = SettableFuture.create();
+        doReturn(firstFuture, secondFuture).when(clientFactory).createClient(any());
         handler.connect();
         assertEquals(1, handler.attempts());
 
-        doReturn(scheduleFuture).when(eventExecutor).schedule(scheduleCaptor.capture(), eq(150L),
+        doReturn(scheduleFuture).when(scheduledExecutor).schedule(scheduleCaptor.capture(), eq(150L),
             eq(TimeUnit.MILLISECONDS));
-        firstPromise.setFailure(new AssertionError("first"));
+        firstFuture.setException(new AssertionError("first"));
 
         assertEquals(2, handler.attempts());
 
         // and when we run the task, we get a clientDispatcher invocation, but attempts are still the same
         scheduleCaptor.getValue().run();
-        verify(clientDispatcher, times(2)).createClient(any());
+        verify(clientFactory, times(2)).createClient(any());
         assertEquals(2, handler.attempts());
 
         // now report the second failure
         final var throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
         doNothing().when(delegate).onDeviceFailed(throwableCaptor.capture());
-        secondPromise.setFailure(new AssertionError("second"));
+        secondFuture.setException(new AssertionError("second"));
         assertThat(throwableCaptor.getValue(), instanceOf(ConnectGivenUpException.class));
 
         // but nothing else happens
         assertEquals(2, handler.attempts());
     }
 
-    // Initiate connect() which results in immediate clientDispatcher report. No interactions with delegate may occur,
+    // Initiate connect() which results in immediate clientDispatcher report. No interactions with delegate may occur,
     // as this is just a prelude to a follow-up callback
-    private void assertSuccessfulConnect() {
-        doReturn(new SucceededFuture<>(ImmediateEventExecutor.INSTANCE, clientSession))
-            .when(clientDispatcher).createClient(any());
+    private void assertSuccessfulConnect() throws Exception {
+        doReturn(Futures.immediateFuture(clientSession)).when(clientFactory).createClient(any());
         handler.connect();
-        verify(clientDispatcher).createClient(any());
+        verify(clientFactory).createClient(any());
         verifyNoInteractions(delegate);
     }
 }
index 2ed801b55f4e7ea512d858d5e3c2fb58257b37c4..434ec5b3f261ac1d86eff3a91114c5d377e64656 100644 (file)
@@ -7,7 +7,7 @@
  */
 package org.opendaylight.netconf.callhome.protocol;
 
-import io.netty.util.concurrent.Future;
+import com.google.common.util.concurrent.ListenableFuture;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
@@ -26,5 +26,5 @@ public interface CallHomeChannelActivator {
      * @param listener Client Session Listener to be attached to NETCONF session.
      * @return Future with negotiated NETCONF session
      */
-    @NonNull Future<NetconfClientSession> activate(@NonNull NetconfClientSessionListener listener);
+    @NonNull ListenableFuture<NetconfClientSession> activate(@NonNull NetconfClientSessionListener listener);
 }
index 8c3d10048eb2ae18eed70fde131a1b0c09598efa..b2e41e7eb0fc5f26a0885de075d257033564b99f 100644 (file)
@@ -11,6 +11,9 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelOutboundHandlerAdapter;
@@ -123,10 +126,10 @@ class CallHomeSessionContext implements CallHomeProtocolSessionContext {
         sshSession.close(false);
     }
 
-    private synchronized Promise<NetconfClientSession> doActivate(final ClientChannel netconfChannel,
+    private synchronized ListenableFuture<NetconfClientSession> doActivate(final ClientChannel netconfChannel,
             final NetconfClientSessionListener listener, final MinaSshNettyChannel nettyChannel) {
         if (activated) {
-            return newSessionPromise().setFailure(new IllegalStateException("Session already activated."));
+            return Futures.immediateFailedFuture(new IllegalStateException("Session already activated."));
         }
         activated = true;
         nettyChannel.pipeline().addFirst(new SshWriteAsyncHandlerAdapter(netconfChannel));
@@ -135,11 +138,21 @@ class CallHomeSessionContext implements CallHomeProtocolSessionContext {
         factory.getChannelInitializer(listener).initialize(nettyChannel, activationPromise);
         ((ChannelSubsystem) netconfChannel).onClose(nettyChannel::doNettyDisconnect);
         factory.getNettyGroup().register(nettyChannel).awaitUninterruptibly(500);
-        return activationPromise;
+        final SettableFuture<NetconfClientSession> future = SettableFuture.create();
+        activationPromise.addListener(ignored -> {
+            final var cause = activationPromise.cause();
+            if (cause != null) {
+                future.setException(cause);
+            } else {
+                future.set(activationPromise.getNow());
+            }
+        });
+        return future;
     }
 
     @Deprecated(since = "7.0.0", forRemoval = true)
-    protected MinaSshNettyChannel newMinaSshNettyChannel() {
+    @VisibleForTesting
+    MinaSshNettyChannel newMinaSshNettyChannel() {
         return new MinaSshNettyChannel(this, sshSession);
     }
 
index f8f9e458ec0bc316277f4510f416bc4e403453c1..b8a5967edcef029e6d5445ba6f76847a55434f81 100644 (file)
@@ -9,6 +9,9 @@ package org.opendaylight.netconf.callhome.protocol.tls;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import io.netty.channel.Channel;
 import io.netty.handler.ssl.SslHandler;
 import io.netty.util.HashedWheelTimer;
@@ -67,10 +70,11 @@ final class CallHomeTlsSessionContext implements CallHomeProtocolSessionContext
         channel.close();
     }
 
-    private Promise<NetconfClientSession> doActivate(final Channel ch, final NetconfClientSessionListener listener) {
+    private ListenableFuture<NetconfClientSession> doActivate(final Channel ch,
+            final NetconfClientSessionListener listener) {
         final Promise<NetconfClientSession> activationPromise = newSessionPromise();
         if (activated.compareAndExchange(false, true)) {
-            return activationPromise.setFailure(new IllegalStateException("Session (channel) already activated."));
+            return Futures.immediateFailedFuture(new IllegalStateException("Session (channel) already activated."));
         }
 
         LOG.info("Activating Netconf channel for {} with {}", getRemoteAddress(), listener);
@@ -79,7 +83,16 @@ final class CallHomeTlsSessionContext implements CallHomeProtocolSessionContext
         final TlsClientChannelInitializer tlsClientChannelInitializer = new TlsClientChannelInitializer(
             sslHandlerFactory, negotiatorFactory, listener);
         tlsClientChannelInitializer.initialize(ch, activationPromise);
-        return activationPromise;
+        final SettableFuture<NetconfClientSession> future = SettableFuture.create();
+        activationPromise.addListener(ignored -> {
+            final var cause = activationPromise.cause();
+            if (cause != null) {
+                future.setException(cause);
+            } else {
+                future.set(activationPromise.getNow());
+            }
+        });
+        return future;
     }
 
     @Override