Rework NETCONF client reconnection 86/106786/8
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 3 Jul 2023 08:32:23 +0000 (10:32 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 5 Jul 2023 00:01:51 +0000 (00:01 +0000)
This patch reworks the way establishing a connection works: we only have
createClient(), which returns a simple future. The logic for
reconnecting the client is now owned by each individual app.

This affects only netconf-topology implementations, which share common
code here in NetconfConnectorDTO and AbstractNetconfTopology. This is
re-shuffled into NetconfNodeHandler, which now encapsulates all the
state as well as the logic to issue reconnects.

JIRA: NETCONF-1070
Change-Id: I8f175329ab2826e46c95dee59c408e71bf453ccf
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
33 files changed:
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/SingleReconnectFuture.java [deleted file]
apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java
apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java
apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.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/NetconfConnectorDTO.java [deleted file]
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java [new file with mode: 0644]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfDispatcher.java
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionPromise.java
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NeverReconnectStrategy.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectFuture.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectImmediatelyStrategy.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectPromise.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategy.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategyFactory.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategy.java [deleted file]
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategyFactory.java [deleted file]
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClientCallable.java
netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java
plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicator.java
plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicatorTest.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcher.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java [deleted file]
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java [deleted file]
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientConfigurationTest.java
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientDispatcherImplTest.java
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfReconnectingClientConfigurationTest.java [deleted file]
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/TestingNetconfClient.java
protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java

index 86ae0725c2091bd2afb48ec8971afd0d2316c099..0164038af93fcd53296461729223325e713344d9 100644 (file)
@@ -25,13 +25,11 @@ import org.opendaylight.netconf.callhome.protocol.CallHomeProtocolSessionContext
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
 import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.osgi.service.component.annotations.Activate;
@@ -115,11 +113,6 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
         return activateChannel(clientConfiguration);
     }
 
-    @Override
-    public ReconnectFuture createReconnectingClient(final NetconfReconnectingClientConfiguration clientConfiguration) {
-        return new SingleReconnectFuture(eventExecutor, activateChannel(clientConfiguration));
-    }
-
     private Future<NetconfClientSession> activateChannel(final NetconfClientConfiguration conf) {
         final InetSocketAddress remoteAddr = conf.getAddress();
         final CallHomeMountSessionContext context = sessionManager().getByAddress(remoteAddr);
diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/SingleReconnectFuture.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/SingleReconnectFuture.java
deleted file mode 100644 (file)
index 121235d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.netconf.callhome.mount;
-
-import static java.util.Objects.requireNonNull;
-
-import io.netty.util.concurrent.DefaultPromise;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import org.opendaylight.netconf.client.NetconfClientSession;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
-import org.opendaylight.yangtools.yang.common.Empty;
-
-final class SingleReconnectFuture extends DefaultPromise<Empty> implements ReconnectFuture {
-    private final Future<NetconfClientSession> sessionFuture;
-
-    SingleReconnectFuture(final EventExecutor eventExecutor, final Future<NetconfClientSession> sessionFuture) {
-        super(eventExecutor);
-        this.sessionFuture = requireNonNull(sessionFuture);
-        sessionFuture.addListener(future -> {
-            if (!isDone()) {
-                if (future.isCancelled()) {
-                    cancel(false);
-                } else if (future.isSuccess()) {
-                    setSuccess(Empty.value());
-                } else {
-                    setFailure(future.cause());
-                }
-            }
-        });
-    }
-
-    @Override
-    public boolean cancel(final boolean mayInterruptIfRunning) {
-        if (super.cancel(mayInterruptIfRunning)) {
-            if (!sessionFuture.isDone()) {
-                sessionFuture.cancel(mayInterruptIfRunning);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public Future<?> firstSessionFuture() {
-        return sessionFuture;
-    }
-}
index b4c8a659fd6e4ce929599fad2b641d6bd7fc982d..6fe9cda6f2d712710aca655612e7c64a44a71fb1 100644 (file)
@@ -37,7 +37,6 @@ import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 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;
@@ -100,13 +99,11 @@ public class CallHomeMountDispatcherTest {
                 NetconfClientConfiguration.NetconfClientProtocol.SSH;
         final NetconfHelloMessageAdditionalHeader additionalHeader = mock(NetconfHelloMessageAdditionalHeader.class);
         final NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
-        final ReconnectStrategy reconnectStrategy = mock(ReconnectStrategy.class);
         final AuthenticationHandler authHandler = mock(AuthenticationHandler.class);
 
         return NetconfClientConfigurationBuilder.create().withProtocol(protocol).withAddress(address)
                 .withConnectionTimeoutMillis(0).withAdditionalHeader(additionalHeader)
-                .withSessionListener(sessionListener).withReconnectStrategy(reconnectStrategy)
-                .withAuthHandler(authHandler).build();
+                .withSessionListener(sessionListener).withAuthHandler(authHandler).build();
     }
 
     @Test
index 7c37b77e0fef279f41bf858c893d76317fec2c3f..5c9b3b01dd0f70c895e60cdfb71fa78ec6df04e6 100644 (file)
@@ -42,8 +42,7 @@ import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.SslHandlerFactory;
-import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
@@ -185,32 +184,32 @@ public class NetconfTopologyImplTest {
                 .setSleepFactor(Decimal64.valueOf("1.5"))
                 .setConnectionTimeoutMillis(Uint32.valueOf(20000));
 
-        final NetconfReconnectingClientConfiguration configuration =
-                spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(true).build(), NODE_ID);
-        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TCP, configuration.getProtocol());
+        final var configuration = spyTopology.getClientConfig(nodeBuilder.setTcpOnly(true).build(), NODE_ID)
+            .withSessionListener(sessionListener).build();
+        assertEquals(NetconfClientProtocol.TCP, configuration.getProtocol());
         assertNotNull(configuration.getAuthHandler());
         assertNull(configuration.getSslHandlerFactory());
 
-        final NetconfReconnectingClientConfiguration configuration2 =
-                spyTopology.getClientConfig(sessionListener, nodeBuilder.setTcpOnly(false).build(), NODE_ID);
-        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration2.getProtocol());
+        final var configuration2 = spyTopology.getClientConfig(nodeBuilder.setTcpOnly(false).build(), NODE_ID)
+            .withSessionListener(sessionListener).build();
+        assertEquals(NetconfClientProtocol.SSH, configuration2.getProtocol());
         assertNotNull(configuration2.getAuthHandler());
         assertNull(configuration2.getSslHandlerFactory());
 
-        final NetconfReconnectingClientConfiguration configuration3 =
-                spyTopology.getClientConfig(sessionListener, nodeBuilder
-                        .setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build(), NODE_ID);
-        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, configuration3.getProtocol());
+        final var configuration3 = spyTopology.getClientConfig(
+            nodeBuilder.setProtocol(new ProtocolBuilder().setName(Name.SSH).build()).build(), NODE_ID)
+            .withSessionListener(sessionListener).build();
+        assertEquals(NetconfClientProtocol.SSH, configuration3.getProtocol());
         assertNotNull(configuration3.getAuthHandler());
         assertNull(configuration3.getSslHandlerFactory());
 
         final var sslHandlerFactory = mock(SslHandlerFactory.class);
         doReturn(sslHandlerFactory).when(sslHandlerFactoryProvider).getSslHandlerFactory(null);
 
-        final NetconfReconnectingClientConfiguration configuration4 =
-                spyTopology.getClientConfig(sessionListener, nodeBuilder
-                        .setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build(), NODE_ID);
-        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, configuration4.getProtocol());
+        final var configuration4 = spyTopology.getClientConfig(
+            nodeBuilder.setProtocol(new ProtocolBuilder().setName(Name.TLS).build()).build(), NODE_ID)
+            .withSessionListener(sessionListener).build();
+        assertEquals(NetconfClientProtocol.TLS, configuration4.getProtocol());
         assertNull(configuration4.getAuthHandler());
         assertSame(sslHandlerFactory, configuration4.getSslHandlerFactory());
     }
index d4d473166a89910e8a313e67acbdb6f800d898d8..4897482aab0e0449f0863f4345be48698d299c4b 100644 (file)
@@ -34,6 +34,7 @@ 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;
@@ -108,7 +109,6 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
 import org.opendaylight.netconf.client.mdsal.impl.DefaultSchemaResourceManager;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
 import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
@@ -274,9 +274,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
         setupSlave();
 
         yangNodeInstanceId = bindingToNormalized.toYangInstanceIdentifier(NODE_INSTANCE_ID);
-        final var future = mock(ReconnectFuture.class);
-        doReturn(future).when(mockClientDispatcher).createReconnectingClient(any());
-        doReturn(future).when(future).firstSessionFuture();
+        doReturn(mock(Future.class)).when(mockClientDispatcher).createClient(any());
 
         LOG.info("****** Setup complete");
     }
index fc7d897c23d05f0cb26d4eb76360cbf524166df1..883ad18de06afc4def4e5fb0533e0e57156e0875 100644 (file)
@@ -10,19 +10,13 @@ package org.opendaylight.netconf.topology.spi;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import io.netty.util.concurrent.EventExecutor;
-import java.net.URL;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.ExecutionException;
+import org.checkerframework.checker.lock.qual.Holding;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
 import org.opendaylight.controller.config.threadpool.ThreadPool;
@@ -30,31 +24,18 @@ 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.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
+import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.client.mdsal.DatastoreBackedPublicKeyAuth;
-import org.opendaylight.netconf.client.mdsal.LibraryModulesSchemas;
-import org.opendaylight.netconf.client.mdsal.LibrarySchemaSourceProvider;
-import org.opendaylight.netconf.client.mdsal.NetconfDevice.SchemaResourcesDTO;
-import org.opendaylight.netconf.client.mdsal.NetconfDeviceBuilder;
-import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
-import org.opendaylight.netconf.client.mdsal.SchemalessNetconfDevice;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
-import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.api.SslHandlerFactoryProvider;
-import org.opendaylight.netconf.client.mdsal.spi.KeepaliveSalFacade;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
-import org.opendaylight.netconf.nettyutil.TimedReconnectStrategyFactory;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
-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.device.rev230430.connection.parameters.Protocol.Name;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev230430.credentials.Credentials;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev230430.credentials.credentials.KeyAuth;
@@ -70,19 +51,13 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.Empty;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public abstract class AbstractNetconfTopology {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
 
-    private final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
+    private final HashMap<NodeId, NetconfNodeHandler> activeConnectors = new HashMap<>();
     private final NetconfClientDispatcher clientDispatcher;
     private final EventExecutor eventExecutor;
     private final DeviceActionFactory deviceActionFactory;
@@ -171,172 +146,63 @@ public abstract class AbstractNetconfTopology {
     }
 
     protected final synchronized void deleteAllNodes() {
-        activeConnectors.values().forEach(NetconfConnectorDTO::close);
+        activeConnectors.values().forEach(NetconfNodeHandler::close);
         activeConnectors.clear();
     }
 
+    @Holding("this")
     protected final void setupConnection(final NodeId nodeId, final Node configNode) {
-        final NetconfNode netconfNode = configNode.augmentation(NetconfNode.class);
-        final NetconfNodeAugmentedOptional nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
+        final var netconfNode = configNode.augmentation(NetconfNode.class);
+        final var nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
 
         requireNonNull(netconfNode.getHost());
         requireNonNull(netconfNode.getPort());
 
-        final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode, nodeOptional);
-        final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
-        final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
-        final NetconfReconnectingClientConfiguration clientConfig =
-                getClientConfig(netconfClientSessionListener, netconfNode, nodeId);
-        final ListenableFuture<Empty> future =
-                deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
+        // Instantiate the handler ...
+        final var deviceId = NetconfNodeUtils.toRemoteDeviceId(nodeId, netconfNode);
+        final var deviceSalFacade = createSalFacade(deviceId, netconfNode.requireLockDatastore());
+        final var nodeHandler = new NetconfNodeHandler(clientDispatcher, eventExecutor, keepaliveExecutor.getExecutor(),
+            baseSchemas, schemaManager, processingExecutor, deviceActionFactory,
+            deviceSalFacade, deviceId, nodeId, netconfNode, nodeOptional, getClientConfig(netconfNode, nodeId));
 
-        activeConnectors.put(nodeId, deviceCommunicatorDTO);
+        // ... record it ...
+        activeConnectors.put(nodeId, nodeHandler);
 
-        Futures.addCallback(future, new FutureCallback<>() {
-            @Override
-            public void onSuccess(final Empty result) {
-                LOG.debug("Connector for {} started succesfully", nodeId.getValue());
-            }
-
-            @Override
-            public void onFailure(final Throwable throwable) {
-                LOG.error("Connector for {} failed", nodeId.getValue(), throwable);
-                // remove this node from active connectors?
-            }
-        }, MoreExecutors.directExecutor());
-    }
-
-    protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
-            final NetconfNodeAugmentedOptional nodeOptional) {
-        final var deviceId = NetconfNodeUtils.toRemoteDeviceId(nodeId, node);
-        final long keepaliveDelay = node.requireKeepaliveDelay().toJava();
-
-        final var deviceSalFacade = createSalFacade(deviceId, node.requireLockDatastore());
-        // The facade we are going it present to NetconfDevice
-        RemoteDeviceHandler salFacade;
-        final KeepaliveSalFacade keepAliveFacade;
-        if (keepaliveDelay > 0) {
-            LOG.info("Adding keepalive facade, for device {}", nodeId);
-            salFacade = keepAliveFacade = new KeepaliveSalFacade(deviceId, deviceSalFacade,
-                keepaliveExecutor.getExecutor(), keepaliveDelay, node.requireDefaultRequestTimeoutMillis().toJava());
-        } else {
-            salFacade = deviceSalFacade;
-            keepAliveFacade = null;
-        }
-
-        // Setup reconnection on empty context, if so configured
-        if (nodeOptional != null && nodeOptional.getIgnoreMissingSchemaSources().getAllowed()) {
-            LOG.warn("Ignoring missing schema sources is not currently implemented for {}", deviceId);
-        }
-
-        final RemoteDevice<NetconfDeviceCommunicator> device;
-        final List<SchemaSourceRegistration<?>> yanglibRegistrations;
-        if (node.requireSchemaless()) {
-            device = new SchemalessNetconfDevice(baseSchemas, deviceId, salFacade);
-            yanglibRegistrations = List.of();
-        } else {
-            final SchemaResourcesDTO resources = schemaManager.getSchemaResources(node.getSchemaCacheDirectory(),
-                nodeId.getValue());
-            device = new NetconfDeviceBuilder()
-                .setReconnectOnSchemasChange(node.requireReconnectOnChangedSchema())
-                .setSchemaResourcesDTO(resources)
-                .setGlobalProcessingExecutor(processingExecutor)
-                .setId(deviceId)
-                .setSalFacade(salFacade)
-                .setDeviceActionFactory(deviceActionFactory)
-                .setBaseSchemas(baseSchemas)
-                .build();
-            yanglibRegistrations = registerDeviceSchemaSources(deviceId, node, resources);
-        }
-
-        final int rpcMessageLimit = node.requireConcurrentRpcLimit().toJava();
-        if (rpcMessageLimit < 1) {
-            LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", deviceId);
-        }
-
-        final var netconfDeviceCommunicator = new NetconfDeviceCommunicator(deviceId, device, rpcMessageLimit,
-            NetconfNodeUtils.extractUserCapabilities(node));
-
-        if (keepAliveFacade != null) {
-            keepAliveFacade.setListener(netconfDeviceCommunicator);
-        }
-
-        return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade, yanglibRegistrations);
+        // ... and start it
+        nodeHandler.connect();
     }
 
     protected RemoteDeviceHandler createSalFacade(final RemoteDeviceId deviceId, final boolean lockDatastore) {
         return new NetconfTopologyDeviceSalFacade(deviceId, mountPointService, lockDatastore, dataBroker);
     }
 
-    private static List<SchemaSourceRegistration<?>> registerDeviceSchemaSources(final RemoteDeviceId remoteDeviceId,
-            final NetconfNode node, final SchemaResourcesDTO resources) {
-        final var yangLibrary = node.getYangLibrary();
-        if (yangLibrary != null) {
-            final Uri uri = yangLibrary.getYangLibraryUrl();
-            if (uri != null) {
-                final List<SchemaSourceRegistration<?>> registrations = new ArrayList<>();
-                final String yangLibURL = uri.getValue();
-                final SchemaSourceRegistry schemaRegistry = resources.getSchemaRegistry();
-
-                // pre register yang library sources as fallback schemas to schema registry
-                final LibraryModulesSchemas schemas;
-                final String yangLibUsername = yangLibrary.getUsername();
-                final String yangLigPassword = yangLibrary.getPassword();
-                if (yangLibUsername != null && yangLigPassword != null) {
-                    schemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
-                } else {
-                    schemas = LibraryModulesSchemas.create(yangLibURL);
-                }
-
-                for (final Map.Entry<SourceIdentifier, URL> entry : schemas.getAvailableModels().entrySet()) {
-                    registrations.add(schemaRegistry.registerSchemaSource(new LibrarySchemaSourceProvider(
-                        remoteDeviceId, schemas.getAvailableModels()),
-                        PotentialSchemaSource.create(entry.getKey(), YangTextSchemaSource.class,
-                            PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
-                }
-                return List.copyOf(registrations);
-            }
-        }
-
-        return List.of();
-    }
+    @VisibleForTesting
+    public NetconfClientConfigurationBuilder getClientConfig(final NetconfNode node, final NodeId nodeId) {
+        final var builder  = NetconfClientConfigurationBuilder.create();
 
-    public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
-                                                                  final NetconfNode node, final NodeId nodeId) {
-        final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
-                node.requireMaxConnectionAttempts().toJava(), node.requireBetweenAttemptsTimeoutMillis().toJava(),
-                node.requireSleepFactor().decimalValue());
-        final NetconfReconnectingClientConfigurationBuilder reconnectingClientConfigurationBuilder;
         final var protocol = node.getProtocol();
         if (node.requireTcpOnly()) {
-            reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
-                    .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP)
-                    .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
+            builder.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP)
+                .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
         } else if (protocol == null || protocol.getName() == Name.SSH) {
-            reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
-                    .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
-                    .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
+            builder.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
+                .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
         } else if (protocol.getName() == Name.TLS) {
-            reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
-                .withSslHandlerFactory(sslHandlerFactoryProvider.getSslHandlerFactory(protocol.getSpecification()))
-                .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS);
+            builder.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS)
+                .withSslHandlerFactory(sslHandlerFactoryProvider.getSslHandlerFactory(protocol.getSpecification()));
         } else {
             throw new IllegalStateException("Unsupported protocol type: " + protocol.getName());
         }
 
-        if (node.getOdlHelloMessageCapabilities() != null) {
-            reconnectingClientConfigurationBuilder.withOdlHelloCapabilities(
-                    Lists.newArrayList(node.getOdlHelloMessageCapabilities().getCapability()));
+        final var helloCapabilities = node.getOdlHelloMessageCapabilities();
+        if (helloCapabilities != null) {
+            builder.withOdlHelloCapabilities(List.copyOf(helloCapabilities.requireCapability()));
         }
 
-        return reconnectingClientConfigurationBuilder
-                .withName(nodeId.getValue())
-                .withAddress(NetconfNodeUtils.toInetSocketAddress(node))
-                .withConnectionTimeoutMillis(node.requireConnectionTimeoutMillis().toJava())
-                .withReconnectStrategy(sf.createReconnectStrategy())
-                .withConnectStrategyFactory(sf)
-                .withSessionListener(listener)
-                .build();
+        return builder
+            .withName(nodeId.getValue())
+            .withAddress(NetconfNodeUtils.toInetSocketAddress(node))
+            .withConnectionTimeoutMillis(node.requireConnectionTimeoutMillis().toJava());
     }
 
     private AuthenticationHandler getHandlerFromCredentials(final Credentials credentials) {
diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfConnectorDTO.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfConnectorDTO.java
deleted file mode 100644 (file)
index 7da4c95..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2020 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 java.util.List;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
-import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
-import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
-
-final class NetconfConnectorDTO implements AutoCloseable {
-    private final @NonNull List<SchemaSourceRegistration<?>> yanglibRegistrations;
-    private final @NonNull NetconfDeviceCommunicator communicator;
-    private final @NonNull RemoteDeviceHandler facade;
-
-    NetconfConnectorDTO(final NetconfDeviceCommunicator communicator, final RemoteDeviceHandler facade,
-            final List<SchemaSourceRegistration<?>> yanglibRegistrations) {
-        this.communicator = requireNonNull(communicator);
-        this.facade = requireNonNull(facade);
-        this.yanglibRegistrations = List.copyOf(yanglibRegistrations);
-    }
-
-    NetconfDeviceCommunicator getCommunicator() {
-        return communicator;
-    }
-
-    NetconfClientSessionListener getSessionListener() {
-        return communicator;
-    }
-
-    @Override
-    public void close() {
-        communicator.close();
-        facade.close();
-        yanglibRegistrations.forEach(SchemaSourceRegistration::close);
-    }
-}
\ No newline at end of file
diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java
new file mode 100644 (file)
index 0000000..84dddf9
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2020 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.util.concurrent.ListeningExecutorService;
+import io.netty.util.concurrent.EventExecutor;
+import io.netty.util.concurrent.Future;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+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.conf.NetconfClientConfiguration;
+import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.netconf.client.mdsal.LibraryModulesSchemas;
+import org.opendaylight.netconf.client.mdsal.LibrarySchemaSourceProvider;
+import org.opendaylight.netconf.client.mdsal.NetconfDevice.SchemaResourcesDTO;
+import org.opendaylight.netconf.client.mdsal.NetconfDeviceBuilder;
+import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
+import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
+import org.opendaylight.netconf.client.mdsal.SchemalessNetconfDevice;
+import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
+import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
+import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
+import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
+import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceHandler;
+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.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;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.concepts.AbstractRegistration;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * All state associated with a NETCONF topology node. Each node handles its own reconnection.
+ */
+final class NetconfNodeHandler extends AbstractRegistration implements RemoteDeviceHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(NetconfNodeHandler.class);
+
+    private final @NonNull List<SchemaSourceRegistration<?>> yanglibRegistrations;
+    private final @NonNull NetconfClientDispatcher clientDispatcher;
+    private final @NonNull NetconfClientConfiguration clientConfig;
+    private final @NonNull NetconfDeviceCommunicator communicator;
+    private final @NonNull RemoteDeviceHandler delegate;
+    private final @NonNull EventExecutor eventExecutor;
+    private final @NonNull RemoteDeviceId deviceId;
+
+    private final long maxAttempts;
+    private final int minSleep;
+    private final double sleepFactor;
+
+    @GuardedBy("this")
+    private long attempts;
+    @GuardedBy("this")
+    private long lastSleep;
+    @GuardedBy("this")
+    private Future<?> currentTask;
+
+    NetconfNodeHandler(final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor,
+            final ScheduledExecutorService keepaliveExecutor, final BaseNetconfSchemas baseSchemas,
+            final SchemaResourceManager schemaManager, final ListeningExecutorService processingExecutor,
+            final DeviceActionFactory deviceActionFactory, final RemoteDeviceHandler delegate,
+            final RemoteDeviceId deviceId, final NodeId nodeId, final NetconfNode node,
+            final NetconfNodeAugmentedOptional nodeOptional, final NetconfClientConfigurationBuilder configBuilder) {
+        this.clientDispatcher = requireNonNull(clientDispatcher);
+        this.eventExecutor = requireNonNull(eventExecutor);
+        this.delegate = requireNonNull(delegate);
+        this.deviceId = requireNonNull(deviceId);
+
+        maxAttempts = node.requireMaxConnectionAttempts().toJava();
+        minSleep = node.requireBetweenAttemptsTimeoutMillis().toJava();
+        sleepFactor = node.requireSleepFactor().doubleValue();
+
+        // Setup reconnection on empty context, if so configured
+        // FIXME: NETCONF-925: implement this
+        if (nodeOptional != null && nodeOptional.getIgnoreMissingSchemaSources().getAllowed()) {
+            LOG.warn("Ignoring missing schema sources is not currently implemented for {}", deviceId);
+        }
+
+        // The facade we are going it present to NetconfDevice
+        RemoteDeviceHandler salFacade;
+        final KeepaliveSalFacade keepAliveFacade;
+        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,
+                node.requireDefaultRequestTimeoutMillis().toJava());
+        } else {
+            salFacade = this;
+            keepAliveFacade = null;
+        }
+
+        final RemoteDevice<NetconfDeviceCommunicator> device;
+        if (node.requireSchemaless()) {
+            device = new SchemalessNetconfDevice(baseSchemas, deviceId, salFacade);
+            yanglibRegistrations = List.of();
+        } else {
+            final var resources = schemaManager.getSchemaResources(node.getSchemaCacheDirectory(), nodeId.getValue());
+            device = new NetconfDeviceBuilder()
+                .setReconnectOnSchemasChange(node.requireReconnectOnChangedSchema())
+                .setSchemaResourcesDTO(resources)
+                .setGlobalProcessingExecutor(processingExecutor)
+                .setId(deviceId)
+                .setSalFacade(salFacade)
+                .setDeviceActionFactory(deviceActionFactory)
+                .setBaseSchemas(baseSchemas)
+                .build();
+            yanglibRegistrations = registerDeviceSchemaSources(deviceId, node, resources);
+        }
+
+        final int rpcMessageLimit = node.requireConcurrentRpcLimit().toJava();
+        if (rpcMessageLimit < 1) {
+            LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", deviceId);
+        }
+
+        communicator = new NetconfDeviceCommunicator(deviceId, device, rpcMessageLimit,
+            NetconfNodeUtils.extractUserCapabilities(node));
+
+        if (keepAliveFacade != null) {
+            keepAliveFacade.setListener(communicator);
+        }
+
+        clientConfig = configBuilder.withSessionListener(communicator).build();
+    }
+
+    synchronized void connect() {
+        lockedConnect();
+    }
+
+    @Holding("this")
+    private void lockedConnect() {
+        currentTask = clientDispatcher.createClient(clientConfig);
+        currentTask.addListener(this::connectComplete);
+    }
+
+    private void connectComplete(final Future<?> future) {
+        final Throwable cause;
+
+        // Locked manipulation of internal state
+        synchronized (this) {
+            // A quick sanity check
+            if (currentTask != future) {
+                LOG.warn("Ignoring connection completion, expected {} actual {}", future, currentTask);
+                return;
+            }
+
+            currentTask = null;
+            cause = future.cause();
+            if (cause == null || cause instanceof CancellationException) {
+                // Success or cancellation, nothing else to do
+                return;
+            }
+
+            LOG.debug("Connection attempt {} to {} failed", attempts, deviceId, cause);
+        }
+
+        // We are invoking callbacks, do not hold locks
+        onDeviceFailed(cause);
+    }
+
+    @Override
+    protected synchronized void removeRegistration() {
+        if (currentTask != null) {
+            currentTask.cancel(false);
+            currentTask = null;
+        }
+
+        communicator.close();
+        delegate.close();
+        yanglibRegistrations.forEach(SchemaSourceRegistration::close);
+    }
+
+    @Override
+    public synchronized void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
+            final NetconfSessionPreferences sessionPreferences, final RemoteDeviceServices services) {
+        attempts = 0;
+    }
+
+    @Override
+    public void onDeviceDisconnected() {
+        delegate.onDeviceDisconnected();
+        scheduleReconnect();
+    }
+
+    @Override
+    public void onDeviceFailed(final Throwable throwable) {
+        LOG.debug("Connection attempt failed", throwable);
+        delegate.onDeviceFailed(throwable);
+        scheduleReconnect();
+    }
+
+    @Override
+    public void onNotification(final DOMNotification domNotification) {
+        delegate.onNotification(domNotification);
+    }
+
+    private synchronized void scheduleReconnect() {
+        if (isClosed()) {
+            return;
+        }
+
+        final long delayMillis;
+
+        // We have exceeded the number of connection attempts
+        if (maxAttempts > 0 && attempts >= maxAttempts) {
+            LOG.info("Failed to connect {} after {} attempts, not attempting", deviceId, attempts);
+            return;
+        }
+
+        // First connection attempt gets initialized to minimum sleep, each subsequent is exponentially backed off
+        // by sleepFactor.
+        if (attempts != 0) {
+            final long nextSleep = (long) (lastSleep * sleepFactor);
+            // check for overflow
+            delayMillis = nextSleep >= 0 ? nextSleep : Long.MAX_VALUE;
+        } else {
+            delayMillis = minSleep;
+        }
+
+        attempts++;
+        lastSleep = delayMillis;
+        LOG.debug("Retrying {} connection attempt {} after {} milliseconds", deviceId, attempts, delayMillis);
+
+        // If we are not sleeping at all, return an already-succeeded future
+        if (delayMillis == 0) {
+            lockedConnect();
+            return;
+        }
+
+        // Schedule a task for the right time. It will also clear the flag.
+        currentTask = eventExecutor.schedule(this::reconnect, delayMillis, TimeUnit.MILLISECONDS);
+    }
+
+    private synchronized void reconnect() {
+        currentTask = null;
+        if (notClosed()) {
+            lockedConnect();
+        }
+    }
+
+    private static List<SchemaSourceRegistration<?>> registerDeviceSchemaSources(final RemoteDeviceId remoteDeviceId,
+            final NetconfNode node, final SchemaResourcesDTO resources) {
+        final var yangLibrary = node.getYangLibrary();
+        if (yangLibrary != null) {
+            final Uri uri = yangLibrary.getYangLibraryUrl();
+            if (uri != null) {
+                final var registrations = new ArrayList<SchemaSourceRegistration<?>>();
+                final var yangLibURL = uri.getValue();
+                final var schemaRegistry = resources.getSchemaRegistry();
+
+                // pre register yang library sources as fallback schemas to schema registry
+                final var yangLibUsername = yangLibrary.getUsername();
+                final var yangLigPassword = yangLibrary.getPassword();
+                final var schemas = yangLibUsername != null && yangLigPassword != null
+                    ? LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword)
+                        : LibraryModulesSchemas.create(yangLibURL);
+
+                for (var entry : schemas.getAvailableModels().entrySet()) {
+                    registrations.add(schemaRegistry.registerSchemaSource(new LibrarySchemaSourceProvider(
+                        remoteDeviceId, schemas.getAvailableModels()),
+                        PotentialSchemaSource.create(entry.getKey(), YangTextSchemaSource.class,
+                            PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+                }
+                return List.copyOf(registrations);
+            }
+        }
+
+        return List.of();
+    }
+}
\ No newline at end of file
index dbe6d830e1ab517b28fa98409055d8cac998f08c..cdfec0b287992f984dca01883e2558831c5e7e39 100644 (file)
@@ -136,15 +136,14 @@ public abstract class AbstractNetconfDispatcher<S extends NetconfSession, L exte
      * Creates a client.
      *
      * @param address remote address
-     * @param strategy Reconnection strategy to be used when initial connection fails
+     * @param initializer Channel initializer
      *
      * @return Future representing the connection process. Its result represents the combined success of TCP connection
      *         as well as session negotiation.
      */
-    protected Future<S> createClient(final InetSocketAddress address, final ReconnectStrategy strategy,
-            final PipelineInitializer<S> initializer) {
+    protected Future<S> createClient(final InetSocketAddress address, final PipelineInitializer<S> initializer) {
         final Bootstrap b = new Bootstrap();
-        final NetconfSessionPromise<S> p = new NetconfSessionPromise<>(executor, address, strategy, b);
+        final NetconfSessionPromise<S> p = new NetconfSessionPromise<>(executor, address, b);
         b.option(ChannelOption.SO_KEEPALIVE, true).handler(
                 new ChannelInitializer<SocketChannel>() {
                     @Override
@@ -167,9 +166,9 @@ public abstract class AbstractNetconfDispatcher<S extends NetconfSession, L exte
      *
      * @param address remote address
      */
-    protected Future<S> createClient(final InetSocketAddress address, final ReconnectStrategy strategy,
-            final Bootstrap bootstrap, final PipelineInitializer<S> initializer) {
-        final NetconfSessionPromise<S> p = new NetconfSessionPromise<>(executor, address, strategy, bootstrap);
+    protected Future<S> createClient(final InetSocketAddress address, final Bootstrap bootstrap,
+            final PipelineInitializer<S> initializer) {
+        final NetconfSessionPromise<S> p = new NetconfSessionPromise<>(executor, address, bootstrap);
 
         bootstrap.handler(
                 new ChannelInitializer<SocketChannel>() {
@@ -184,30 +183,6 @@ public abstract class AbstractNetconfDispatcher<S extends NetconfSession, L exte
         return p;
     }
 
-    /**
-     * Creates a reconnecting client.
-     *
-     * @param address remote address
-     * @param connectStrategyFactory Factory for creating reconnection strategy for every reconnect attempt
-     * @return Future representing the reconnection task. It will report completion based on reestablishStrategy, e.g.
-     *         success is never reported, only failure when it runs out of reconnection attempts.
-     */
-    protected ReconnectFuture createReconnectingClient(final InetSocketAddress address,
-            final ReconnectStrategyFactory connectStrategyFactory, final PipelineInitializer<S> initializer) {
-        final Bootstrap b = new Bootstrap();
-
-        final ReconnectPromise<S, L> p = new ReconnectPromise<>(GlobalEventExecutor.INSTANCE, this, address,
-                connectStrategyFactory, b, initializer);
-
-        b.option(ChannelOption.SO_KEEPALIVE, true);
-
-        setWorkerGroup(b);
-        setChannelFactory(b);
-
-        p.connect();
-        return p;
-    }
-
     private static void setChannelFactory(final Bootstrap bootstrap) {
         // There is no way to detect if this was already set by
         // customizeBootstrap()
index 4a8fb7f88c897b885eff082010e7b55898a165a6..677f30f37f0fda0c4f5fe3f69327c3e85bcd142d 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.netconf.nettyutil;
 
-import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
 import io.netty.bootstrap.Bootstrap;
@@ -15,7 +14,6 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
 import io.netty.util.concurrent.DefaultPromise;
 import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
 import java.net.InetSocketAddress;
 import org.checkerframework.checker.lock.qual.GuardedBy;
@@ -26,34 +24,21 @@ import org.slf4j.LoggerFactory;
 @Deprecated
 final class NetconfSessionPromise<S extends NetconfSession> extends DefaultPromise<S> {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfSessionPromise.class);
-    private final ReconnectStrategy strategy;
-    private InetSocketAddress address;
+
     private final Bootstrap bootstrap;
+    private InetSocketAddress address;
 
     @GuardedBy("this")
-    private Future<?> pending;
+    private ChannelFuture pending;
 
-    NetconfSessionPromise(final EventExecutor executor, final InetSocketAddress address,
-            final ReconnectStrategy strategy, final Bootstrap bootstrap) {
+    NetconfSessionPromise(final EventExecutor executor, final InetSocketAddress address, final Bootstrap bootstrap) {
         super(executor);
-        this.strategy = requireNonNull(strategy);
         this.address = requireNonNull(address);
         this.bootstrap = requireNonNull(bootstrap);
     }
 
     @SuppressWarnings("checkstyle:illegalCatch")
     synchronized void connect() {
-        final int timeout;
-        try {
-            timeout = strategy.getConnectTimeout();
-        } catch (Exception e) {
-            LOG.info("Connection to {} aborted due to strategy decision", address, e);
-            setFailure(e);
-            return;
-        }
-
-        LOG.debug("Promise {} attempting connect for {}ms", this, timeout);
-
         final ChannelFuture connectFuture;
         try {
             if (address.isUnresolved()) {
@@ -84,14 +69,12 @@ final class NetconfSessionPromise<S extends NetconfSession> extends DefaultPromi
     @Override
     public synchronized Promise<S> setSuccess(final S result) {
         LOG.debug("Promise {} completed", this);
-        strategy.reconnectSuccessful();
         return super.setSuccess(result);
     }
 
     // Triggered when a connection attempt is resolved.
     private synchronized void channelConnectComplete(final ChannelFuture cf) {
         LOG.debug("Promise {} connection resolved", this);
-        verify(pending == cf, "Completed channel future %s while pending %s", cf, pending);
 
         /*
          * The promise we gave out could have been cancelled,
@@ -116,31 +99,6 @@ final class NetconfSessionPromise<S extends NetconfSession> extends DefaultPromi
         }
 
         LOG.debug("Attempt to connect to {} failed", address, cf.cause());
-
-        final Future<Void> rf = strategy.scheduleReconnect(cf.cause());
-        pending = rf;
-        rf.addListener(this::reconnectFutureComplete);
-    }
-
-    // Triggered when a connection attempt is to be made.
-    private synchronized void reconnectFutureComplete(final Future<?> sf) {
-        LOG.debug("Promise {} strategy triggered reconnect", this);
-        verify(pending == sf, "Completed strategy future %s while pending %s", sf, pending);
-
-        /*
-         * The promise we gave out could have been cancelled,
-         * which cascades to the reconnect attempt getting
-         * cancelled, but there is a slight race window, where
-         * the reconnect attempt is already enqueued, but the
-         * listener has not yet been notified -- if cancellation
-         * happens at that point, we need to catch it here.
-         */
-        if (!isCancelled()) {
-            if (sf.isSuccess()) {
-                connect();
-            } else {
-                setFailure(sf.cause());
-            }
-        }
+        setFailure(cf.cause());
     }
 }
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NeverReconnectStrategy.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NeverReconnectStrategy.java
deleted file mode 100644 (file)
index f3a46ba..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-
-/**
- * Utility ReconnectStrategy singleton, which will cause the reconnect process to always fail. This class is thred-safe.
- */
-@Deprecated
-public final class NeverReconnectStrategy implements ReconnectStrategy {
-    private final EventExecutor executor;
-    private final int timeout;
-
-    public NeverReconnectStrategy(final EventExecutor executor, final int timeout) {
-        checkArgument(timeout >= 0);
-        this.executor = requireNonNull(executor);
-        this.timeout = timeout;
-    }
-
-    @Override
-    public Future<Void> scheduleReconnect(final Throwable cause) {
-        return executor.newFailedFuture(new Throwable("Reconnect failed", cause));
-    }
-
-    @Override
-    public void reconnectSuccessful() {
-        // Nothing to do
-    }
-
-    @Override
-    public int getConnectTimeout() {
-        return timeout;
-    }
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectFuture.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectFuture.java
deleted file mode 100644 (file)
index 62fc049..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.netconf.nettyutil;
-
-import com.google.common.annotations.Beta;
-import io.netty.util.concurrent.Future;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.Empty;
-
-/**
- * A future representing the task of reconnecting of a certain channel. This future never completes successfully, it
- * either fails when the underlying strategy gives up, or when it is cancelled. It additionally exposes an additional
- * future, which completes when the session is established for the first time.
- */
-@Beta
-public interface ReconnectFuture extends Future<Empty> {
-    /**
-     * Return a Future which completes when the first session is established.
-     *
-     * @return First session establishment future
-     */
-    @NonNull Future<?> firstSessionFuture();
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectImmediatelyStrategy.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectImmediatelyStrategy.java
deleted file mode 100644 (file)
index da0c5e5..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Utility ReconnectStrategy singleton, which will cause the reconnect process to immediately schedule a reconnection
- * attempt. This class is thread-safe.
- */
-@Deprecated
-public final class ReconnectImmediatelyStrategy implements ReconnectStrategy {
-    private static final Logger LOG = LoggerFactory.getLogger(ReconnectImmediatelyStrategy.class);
-    private final EventExecutor executor;
-    private final int timeout;
-
-    public ReconnectImmediatelyStrategy(final EventExecutor executor, final int timeout) {
-        checkArgument(timeout >= 0);
-        this.executor = requireNonNull(executor);
-        this.timeout = timeout;
-    }
-
-    @Override
-    public Future<Void> scheduleReconnect(final Throwable cause) {
-        LOG.debug("Connection attempt failed", cause);
-        return executor.newSucceededFuture(null);
-    }
-
-    @Override
-    public void reconnectSuccessful() {
-        // Nothing to do
-    }
-
-    @Override
-    public int getConnectTimeout() {
-        return timeout;
-    }
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectPromise.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectPromise.java
deleted file mode 100644 (file)
index 4537fcd..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-import static java.util.Objects.requireNonNull;
-
-import io.netty.bootstrap.Bootstrap;
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.util.concurrent.DefaultPromise;
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.Promise;
-import java.net.InetSocketAddress;
-import org.checkerframework.checker.lock.qual.GuardedBy;
-import org.checkerframework.checker.lock.qual.Holding;
-import org.opendaylight.netconf.api.NetconfSession;
-import org.opendaylight.netconf.api.NetconfSessionListener;
-import org.opendaylight.netconf.nettyutil.AbstractNetconfDispatcher.PipelineInitializer;
-import org.opendaylight.yangtools.yang.common.Empty;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Deprecated
-final class ReconnectPromise<S extends NetconfSession, L extends NetconfSessionListener<? super S>>
-        extends DefaultPromise<Empty> implements ReconnectFuture {
-    private static final Logger LOG = LoggerFactory.getLogger(ReconnectPromise.class);
-
-    private final AbstractNetconfDispatcher<S, L> dispatcher;
-    private final InetSocketAddress address;
-    private final ReconnectStrategyFactory strategyFactory;
-    private final Bootstrap bootstrap;
-    private final PipelineInitializer<S> initializer;
-    private final Promise<Empty> firstSessionFuture;
-
-    @GuardedBy("this")
-    private Future<?> pending;
-
-    ReconnectPromise(final EventExecutor executor, final AbstractNetconfDispatcher<S, L> dispatcher,
-            final InetSocketAddress address, final ReconnectStrategyFactory connectStrategyFactory,
-            final Bootstrap bootstrap, final PipelineInitializer<S> initializer) {
-        super(executor);
-        this.firstSessionFuture = new DefaultPromise<>(executor);
-        this.bootstrap = requireNonNull(bootstrap);
-        this.initializer = requireNonNull(initializer);
-        this.dispatcher = requireNonNull(dispatcher);
-        this.address = requireNonNull(address);
-        this.strategyFactory = requireNonNull(connectStrategyFactory);
-    }
-
-    @Override
-    public synchronized boolean cancel(final boolean mayInterruptIfRunning) {
-        if (super.cancel(mayInterruptIfRunning)) {
-            firstSessionFuture.cancel(mayInterruptIfRunning);
-            pending.cancel(mayInterruptIfRunning);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public Future<?> firstSessionFuture() {
-        return firstSessionFuture;
-    }
-
-    synchronized void connect() {
-        lockedConnect();
-    }
-
-    @Holding("this")
-    private void lockedConnect() {
-        final ReconnectStrategy cs = strategyFactory.createReconnectStrategy();
-
-        // Set up a client with pre-configured bootstrap, but add a closed channel handler into the pipeline to support
-        // reconnect attempts
-        pending = dispatcher.createClient(address, cs, bootstrap, (channel, promise) -> {
-            initializer.initializeChannel(channel, promise);
-            // add closed channel handler
-            // This handler has to be added as last channel handler and the channel inactive event has to be caught by
-            // it
-            // Handlers in front of it can react to channelInactive event, but have to forward the event or the
-            // reconnect will not work
-            // This handler is last so all handlers in front of it can handle channel inactive (to e.g. resource
-            // cleanup) before a new connection is started
-            channel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
-                @Override
-                public void channelInactive(final ChannelHandlerContext ctx) {
-                    onChannelInactive();
-                }
-            });
-        });
-
-        if (!firstSessionFuture.isDone()) {
-            pending.addListener(future -> {
-                if (!future.isSuccess() && !firstSessionFuture.isDone()) {
-                    firstSessionFuture.setFailure(future.cause());
-                }
-            });
-        }
-    }
-
-    private void onChannelInactive() {
-        // This is the ultimate channel inactive handler, not forwarding
-        if (isCancelled()) {
-            return;
-        }
-
-        synchronized (this) {
-            final Future<?> attempt = pending;
-            if (!attempt.isDone() || !attempt.isSuccess()) {
-                // Connection refused, negotiation failed, or similar
-                LOG.debug("Connection to {} was dropped during negotiation, reattempting", address);
-            }
-
-            LOG.debug("Reconnecting after connection to {} was dropped", address);
-            lockedConnect();
-        }
-    }
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategy.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategy.java
deleted file mode 100644 (file)
index 55e6b03..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-import io.netty.util.concurrent.Future;
-
-/**
- * Interface exposed by a reconnection strategy provider. A reconnection
- * strategy decides whether to attempt reconnection and when to do that.
- *
- * <p>
- * The proper way of using this API is such that when a connection attempt
- * has failed, the user will call scheduleReconnect() to obtain a future,
- * which tracks schedule of the next connect attempt. The user should add its
- * own listener to be get notified when the future is done. Once the
- * the notification fires, user should examine the future to see whether
- * it is successful or not. If it is successful, the user should immediately
- * initiate a connection attempt. If it is unsuccessful, the user must
- * not attempt any more connection attempts and should abort the reconnection
- * process.
- */
-@Deprecated
-public interface ReconnectStrategy {
-    /**
-     * Query the strategy for the connect timeout.
-     *
-     * @return connect try timeout in milliseconds, or
-     *         0 for infinite (or system-default) timeout
-     * @throws Exception if the connection should not be attempted
-     */
-    int getConnectTimeout() throws Exception;
-
-    /**
-     * Schedule a connection attempt. The precise time when the connection
-     * should be attempted is signaled by successful completion of returned
-     * future.
-     *
-     * @param cause Cause of previous failure
-     * @return a future tracking the schedule, may not be null
-     * @throws IllegalStateException when a connection attempt is currently
-     *         scheduled.
-     */
-    Future<Void> scheduleReconnect(Throwable cause);
-
-    /**
-     * Reset the strategy state. Users call this method once the reconnection
-     * process succeeds.
-     */
-    void reconnectSuccessful();
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategyFactory.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategyFactory.java
deleted file mode 100644 (file)
index 275e9b9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-/**
- * Factory interface for creating new ReconnectStrategy instances. This is
- * primarily useful for allowing injection of a specific type of strategy for
- * on-demand use, pretty much like you would use a ThreadFactory.
- */
-@Deprecated
-public interface ReconnectStrategyFactory {
-    /**
-     * Create a new ReconnectStrategy.
-     *
-     * @return a new reconnecty strategy
-     */
-    ReconnectStrategy createReconnectStrategy();
-}
-
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategy.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategy.java
deleted file mode 100644 (file)
index 895ebb2..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.nettyutil;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-
-import io.netty.util.concurrent.EventExecutor;
-import io.netty.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import org.checkerframework.checker.lock.qual.GuardedBy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Swiss army knife equivalent for reconnect strategies. This class is thread-safe.
- *
- * <p>
- * This strategy continues to schedule reconnect attempts, each having to complete in a fixed time (connectTime).
- *
- * <p>
- * Initial sleep time is specified as minSleep. Each subsequent unsuccessful attempt multiplies this time by a constant
- * factor (sleepFactor) -- this allows for either constant reconnect times (sleepFactor = 1), or various degrees of
- * exponential back-off (sleepFactor &gt; 1). Maximum sleep time between attempts can be capped to a specific value
- * (maxSleep).
- *
- * <p>
- * The strategy can optionally give up based on two criteria:
- *
- * <p>
- * A preset number of connection retries (maxAttempts) has been reached, or
- *
- * <p>
- * A preset absolute deadline is reached (deadline nanoseconds, as reported by System.nanoTime(). In this specific case,
- * both connectTime and maxSleep will be controlled such that the connection attempt is resolved as closely to the
- * deadline as possible.
- *
- * <p>
- * Both these caps can be combined, with the strategy giving up as soon as the first one is reached.
- */
-@Deprecated
-public final class TimedReconnectStrategy implements ReconnectStrategy {
-    private static final Logger LOG = LoggerFactory.getLogger(TimedReconnectStrategy.class);
-    private final EventExecutor executor;
-    private final Long deadline;
-    private final Long maxAttempts;
-    private final Long maxSleep;
-    private final double sleepFactor;
-    private final int connectTime;
-    private final long minSleep;
-
-    @GuardedBy("this")
-    private long attempts;
-
-    @GuardedBy("this")
-    private long lastSleep;
-
-    @GuardedBy("this")
-    private boolean scheduled;
-
-    public TimedReconnectStrategy(final EventExecutor executor, final int connectTime, final long minSleep,
-            final double sleepFactor, final Long maxSleep, final Long maxAttempts, final Long deadline) {
-        checkArgument(maxSleep == null || minSleep <= maxSleep);
-        checkArgument(sleepFactor >= 1);
-        checkArgument(connectTime >= 0);
-        this.executor = requireNonNull(executor);
-        this.deadline = deadline;
-        this.maxAttempts = maxAttempts;
-        this.minSleep = minSleep;
-        this.maxSleep = maxSleep;
-        this.sleepFactor = sleepFactor;
-        this.connectTime = connectTime;
-    }
-
-    @Override
-    public synchronized Future<Void> scheduleReconnect(final Throwable cause) {
-        LOG.debug("Connection attempt failed", cause);
-
-        // Check if a reconnect attempt is scheduled
-        checkState(!this.scheduled);
-
-        // Get a stable 'now' time for deadline calculations
-        final long now = System.nanoTime();
-
-        // Obvious stop conditions
-        if (this.maxAttempts != null && this.attempts >= this.maxAttempts) {
-            return this.executor.newFailedFuture(new Throwable("Maximum reconnection attempts reached"));
-        }
-        if (this.deadline != null && this.deadline <= now) {
-            return this.executor.newFailedFuture(new TimeoutException("Reconnect deadline reached"));
-        }
-
-        /*
-         * First connection attempt gets initialized to minimum sleep,
-         * each subsequent is exponentially backed off by sleepFactor.
-         */
-        if (this.attempts != 0) {
-            this.lastSleep *= this.sleepFactor;
-        } else {
-            this.lastSleep = this.minSleep;
-        }
-
-        // Cap the sleep time to maxSleep
-        if (this.maxSleep != null && this.lastSleep > this.maxSleep) {
-            LOG.debug("Capped sleep time from {} to {}", this.lastSleep, this.maxSleep);
-            this.lastSleep = this.maxSleep;
-        }
-
-        this.attempts++;
-
-        // Check if the reconnect attempt is within the deadline
-        if (this.deadline != null && this.deadline <= now + TimeUnit.MILLISECONDS.toNanos(this.lastSleep)) {
-            return this.executor.newFailedFuture(new TimeoutException("Next reconnect would happen after deadline"));
-        }
-
-        LOG.debug("Connection attempt {} sleeping for {} milliseconds", this.attempts, this.lastSleep);
-
-        // If we are not sleeping at all, return an already-succeeded future
-        if (this.lastSleep == 0) {
-            return this.executor.newSucceededFuture(null);
-        }
-
-        // Set the scheduled flag.
-        this.scheduled = true;
-
-        // Schedule a task for the right time. It will also clear the flag.
-        return this.executor.schedule(() -> {
-            synchronized (TimedReconnectStrategy.this) {
-                checkState(TimedReconnectStrategy.this.scheduled);
-                TimedReconnectStrategy.this.scheduled = false;
-            }
-
-            return null;
-        }, this.lastSleep, TimeUnit.MILLISECONDS);
-    }
-
-    @Override
-    public synchronized void reconnectSuccessful() {
-        checkState(!this.scheduled);
-        this.attempts = 0;
-    }
-
-    @Override
-    public int getConnectTimeout() throws TimeoutException {
-        int timeout = this.connectTime;
-
-        if (this.deadline != null) {
-
-            // If there is a deadline, we may need to cap the connect
-            // timeout to meet the deadline.
-            final long now = System.nanoTime();
-            if (now >= this.deadline) {
-                throw new TimeoutException("Reconnect deadline already passed");
-            }
-
-            final long left = TimeUnit.NANOSECONDS.toMillis(this.deadline - now);
-            if (left < 1) {
-                throw new TimeoutException("Connect timeout too close to deadline");
-            }
-
-            /*
-             * A bit of magic:
-             * - if time left is less than the timeout, set it directly
-             * - if there is no timeout, and time left is:
-             *      - less than maximum integer, set timeout to time left
-             *      - more than maximum integer, set timeout Integer.MAX_VALUE
-             */
-            if (timeout > left) {
-                timeout = (int) left;
-            } else if (timeout == 0) {
-                timeout = left <= Integer.MAX_VALUE ? (int) left : Integer.MAX_VALUE;
-            }
-        }
-        return timeout;
-    }
-}
diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategyFactory.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategyFactory.java
deleted file mode 100644 (file)
index bf26187..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2019 Pantheon Technologies, 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.nettyutil;
-
-import io.netty.util.concurrent.EventExecutor;
-import java.math.BigDecimal;
-
-@Deprecated
-public final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
-    private final Long connectionAttempts;
-    private final EventExecutor executor;
-    private final double sleepFactor;
-    private final int minSleep;
-
-    public TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts,
-                                  final int minSleep, final BigDecimal sleepFactor) {
-        if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
-            connectionAttempts = maxConnectionAttempts;
-        } else {
-            connectionAttempts = null;
-        }
-
-        this.sleepFactor = sleepFactor.doubleValue();
-        this.executor = executor;
-        this.minSleep = minSleep;
-    }
-
-    @Override
-    public ReconnectStrategy createReconnectStrategy() {
-        return new TimedReconnectStrategy(executor, minSleep,
-                minSleep, sleepFactor, null /*maxSleep*/, connectionAttempts, null /*deadline*/);
-    }
-}
\ No newline at end of file
index b295bbf2f7aa2f9c8695b09425415cdf6cf7dc1f..0de06d9012e89997d64b30a58d41a4ec85c1e4ca 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.netconf.test.tool.client.stress;
 
-import io.netty.util.concurrent.GlobalEventExecutor;
 import java.net.InetSocketAddress;
 import java.util.List;
 import java.util.concurrent.Callable;
@@ -21,7 +20,6 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
-import org.opendaylight.netconf.nettyutil.NeverReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -81,10 +79,14 @@ public class StressClientCallable implements Callable<Boolean> {
 
     private static NetconfClientConfiguration getNetconfClientConfiguration(final Parameters params,
             final NetconfDeviceCommunicator sessionListener) {
-        final NetconfClientConfigurationBuilder netconfClientConfigurationBuilder = NetconfClientConfigurationBuilder
-            .create();
-        netconfClientConfigurationBuilder.withSessionListener(sessionListener);
-        netconfClientConfigurationBuilder.withAddress(params.getInetAddress());
+        final var netconfClientConfigurationBuilder = NetconfClientConfigurationBuilder.create()
+            .withSessionListener(sessionListener)
+            .withAddress(params.getInetAddress())
+            .withProtocol(params.ssh ? NetconfClientConfiguration.NetconfClientProtocol.SSH
+                : NetconfClientConfiguration.NetconfClientProtocol.TCP)
+            .withAuthHandler(new LoginPasswordHandler(params.username, params.password))
+            .withConnectionTimeoutMillis(20000L);
+
         if (params.tcpHeader != null) {
             final String header = params.tcpHeader.replace("\"", "").trim() + "\n";
             netconfClientConfigurationBuilder.withAdditionalHeader(
@@ -96,12 +98,6 @@ public class StressClientCallable implements Callable<Boolean> {
                     }
                 });
         }
-        netconfClientConfigurationBuilder.withProtocol(params.ssh ? NetconfClientConfiguration.NetconfClientProtocol.SSH
-            : NetconfClientConfiguration.NetconfClientProtocol.TCP);
-        netconfClientConfigurationBuilder.withAuthHandler(new LoginPasswordHandler(params.username, params.password));
-        netconfClientConfigurationBuilder.withConnectionTimeoutMillis(20000L);
-        netconfClientConfigurationBuilder.withReconnectStrategy(
-            new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));
         return netconfClientConfigurationBuilder.build();
     }
 }
index c2eaa8dcce0373c5afc95dea70f6cddbd589f351..4e29072ad40b4a63032aed9a3fb509222bab7d5e 100644 (file)
@@ -16,7 +16,6 @@ import com.google.common.collect.ImmutableMap;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.DefaultThreadFactory;
-import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.File;
 import java.net.InetSocketAddress;
 import java.util.Map;
@@ -39,7 +38,6 @@ import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.NeverReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
 import org.opendaylight.netconf.test.tool.config.Configuration;
 import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder;
@@ -206,7 +204,6 @@ public class TestToolTest {
             .build();
     }
 
-    @SuppressWarnings("deprecation")
     private static NetconfClientConfiguration getClientConfig(final String host, final int port,
                                                               final Configuration simulatorConfig,
                                                               final NetconfClientSessionListener sessionListener) {
@@ -214,8 +211,6 @@ public class TestToolTest {
         return NetconfClientConfigurationBuilder.create()
             .withAddress(new InetSocketAddress(host, port))
             .withSessionListener(sessionListener)
-            .withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS))
             .withProtocol(simulatorConfig.isSsh() ? NetconfClientProtocol.SSH : NetconfClientProtocol.TCP)
             .withAuthHandler(new LoginPasswordHandler(user.username, user.password))
             .build();
index 4e8e680a0a4160fd56c4229386a1acf8b906ac61..5edf44fce05927feb8b3c3eacc1e1e52fd215647 100644 (file)
@@ -11,8 +11,6 @@ import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import io.netty.util.concurrent.Future;
 import java.io.EOFException;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -30,17 +28,13 @@ import org.opendaylight.netconf.api.NetconfTerminationReason;
 import org.opendaylight.netconf.api.xml.XmlElement;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.netconf.api.xml.XmlUtil;
-import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.NetconfMessageUtil;
-import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceCommunicator;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
-import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
 import org.opendaylight.yangtools.yang.common.ErrorType;
@@ -65,9 +59,6 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
     private final Queue<Request> requests = new ArrayDeque<>();
     private NetconfClientSession currentSession;
 
-    private final SettableFuture<Empty> firstConnectionFuture = SettableFuture.create();
-    private Future<?> taskFuture;
-
     // isSessionClosing indicates a close operation on the session is issued and
     // tearDown will surely be called later to finish the close.
     // Used to allow only one thread to enter tearDown and other threads should
@@ -124,48 +115,6 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
         } finally {
             sessionLock.unlock();
         }
-
-        // FIXME: right, except ... this does not include the device schema setup, so is it really useful?
-        if (!firstConnectionFuture.set(Empty.value())) {
-            LOG.trace("{}: First connection already completed", id);
-        }
-    }
-
-    /**
-     * Initialize remote connection.
-     *
-     * @param dispatcher {@code NetconfCLientDispatcher}
-     * @param config     {@code NetconfClientConfiguration}
-     * @return a ListenableFuture that returns success on first successful connection and failure when the underlying
-     *         reconnecting strategy runs out of reconnection attempts
-     */
-    public ListenableFuture<Empty> initializeRemoteConnection(final NetconfClientDispatcher dispatcher,
-            final NetconfClientConfiguration config) {
-
-        final Future<?> connectFuture;
-        if (config instanceof NetconfReconnectingClientConfiguration) {
-            // FIXME: This is weird. If I understand it correctly we want to know about the first connection so as to
-            //        forward error state. Analyze the call graph to understand what is going on here. We really want
-            //        to move reconnection away from the socket layer, so that it can properly interface with sessions
-            //        and generally has some event-driven state (as all good network glue does). There is a second story
-            //        which is we want to avoid duplicate code, so it depends on other users as well.
-            final var future = dispatcher.createReconnectingClient((NetconfReconnectingClientConfiguration) config);
-            taskFuture = future;
-            connectFuture = future.firstSessionFuture();
-        } else {
-            taskFuture = connectFuture = dispatcher.createClient(config);
-        }
-
-        connectFuture.addListener(future -> {
-            if (!future.isSuccess() && !future.isCancelled()) {
-                LOG.debug("{}: Connection failed", id, future.cause());
-                remoteDevice.onRemoteSessionFailed(future.cause());
-                if (!firstConnectionFuture.isDone()) {
-                    firstConnectionFuture.setException(future.cause());
-                }
-            }
-        });
-        return firstConnectionFuture;
     }
 
     public void disconnect() {
@@ -252,10 +201,6 @@ public class NetconfDeviceCommunicator implements NetconfClientSessionListener,
 
     @Override
     public void close() {
-        // Cancel reconnect if in progress
-        if (taskFuture != null) {
-            taskFuture.cancel(false);
-        }
         // Disconnect from device
         // tear down not necessary, called indirectly by the close in disconnect()
         disconnect();
index 1f283eaa0060d51cd8693a9dacbfb15c7851fbfc..53989409ec5f0b6c23adfa9adecba5c69f7e3620 100644 (file)
@@ -20,8 +20,6 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.withSettings;
 
@@ -30,13 +28,8 @@ import com.google.common.base.Strings;
 import com.google.common.util.concurrent.ListenableFuture;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
-import io.netty.channel.EventLoopGroup;
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
-import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.ByteArrayInputStream;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
@@ -57,19 +50,12 @@ import org.opendaylight.netconf.api.NamespaceURN;
 import org.opendaylight.netconf.api.NetconfMessage;
 import org.opendaylight.netconf.api.NetconfTerminationReason;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
-import org.opendaylight.netconf.client.NetconfClientDispatcherImpl;
 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.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.TimedReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
@@ -388,60 +374,6 @@ public class NetconfDeviceCommunicatorTest {
                 errorInfoMessages.contains(errMsg1) && errorInfoMessages.contains(errMsg2));
     }
 
-    /**
-     * Test whether reconnect is scheduled properly.
-     */
-    @Test
-    public void testNetconfDeviceReconnectInCommunicator() {
-        final RemoteDevice<NetconfDeviceCommunicator> device = mock(RemoteDevice.class);
-
-        final TimedReconnectStrategy timedReconnectStrategy =
-                new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, 10000, 0, 1.0, null, 100L, null);
-        final ReconnectStrategy reconnectStrategy = spy(new ReconnectStrategy() {
-            @Override
-            @Deprecated
-            public int getConnectTimeout() throws Exception {
-                return timedReconnectStrategy.getConnectTimeout();
-            }
-
-            @Override
-            @Deprecated
-            public Future<Void> scheduleReconnect(final Throwable cause) {
-                return timedReconnectStrategy.scheduleReconnect(cause);
-            }
-
-            @Override
-            @Deprecated
-            public void reconnectSuccessful() {
-                timedReconnectStrategy.reconnectSuccessful();
-            }
-        });
-
-        final EventLoopGroup group = new NioEventLoopGroup();
-        final Timer time = new HashedWheelTimer();
-        try {
-            final NetconfDeviceCommunicator listener = new NetconfDeviceCommunicator(
-                    new RemoteDeviceId("test", InetSocketAddress.createUnresolved("localhost", 22)), device, 10);
-            final NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
-                    .withAddress(new InetSocketAddress("localhost", 65000))
-                    .withReconnectStrategy(reconnectStrategy)
-                    .withConnectStrategyFactory(() -> reconnectStrategy)
-                    .withAuthHandler(new LoginPasswordHandler("admin", "admin"))
-                    .withConnectionTimeoutMillis(10000)
-                    .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
-                    .withSessionListener(listener)
-                    .build();
-
-            listener.initializeRemoteConnection(new NetconfClientDispatcherImpl(group, group, time), cfg);
-
-            verify(reconnectStrategy,
-                    timeout(TimeUnit.MINUTES.toMillis(4)).times(101)).scheduleReconnect(any(Throwable.class));
-        } finally {
-            time.stop();
-            group.shutdownGracefully();
-        }
-    }
-
     @Test
     public void testOnResponseMessageWithWrongMessageID() throws Exception {
         setupSession();
@@ -483,8 +415,9 @@ public class NetconfDeviceCommunicatorTest {
 
     private static NetconfMessage createMultiErrorResponseMessage(final String messageID) throws Exception {
         // multiple rpc-errors which simulate actual response like in NETCONF-666
-        String xmlStr = "<nc:rpc-reply xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:junos=\"http://xml.juniper.net/junos/18.4R1/junos\""
-                + "           message-id=\"" + messageID + "\">"
+        String xmlStr = "<nc:rpc-reply xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                + "xmlns:junos=\"http://xml.juniper.net/junos/18.4R1/junos\" message-id=\"" + messageID + "\">"
                 + "<nc:rpc-error>\n"
                 + "<nc:error-type>protocol</nc:error-type>\n"
                 + "<nc:error-tag>operation-failed</nc:error-tag>\n"
index b1d2a12468fdc9f6423de6b6bffc778510a0ef18..ed3b3c6dba4b28e9ec673331425df74681cb9844 100644 (file)
@@ -9,11 +9,8 @@ package org.opendaylight.netconf.client;
 
 import io.netty.util.concurrent.Future;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
 
 public interface NetconfClientDispatcher {
-
     /**
      * Create netconf client. Network communication has to be set up based on network protocol specified in
      * clientConfiguration
@@ -22,6 +19,4 @@ public interface NetconfClientDispatcher {
      * @return netconf client based on provided configuration
      */
     Future<NetconfClientSession> createClient(NetconfClientConfiguration clientConfiguration);
-
-    ReconnectFuture createReconnectingClient(NetconfReconnectingClientConfiguration clientConfiguration);
 }
index ef8fb66d57d9057820661dbb1f0d12a7f0a66ab9..33454c2dfd39b00ba94251e809b9c16a93ee04b2 100644 (file)
@@ -18,9 +18,7 @@ import java.util.Set;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
 import org.opendaylight.netconf.nettyutil.AbstractNetconfDispatcher;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -59,72 +57,30 @@ public class NetconfClientDispatcherImpl
         };
     }
 
-    @Override
-    public ReconnectFuture createReconnectingClient(final NetconfReconnectingClientConfiguration clientConfiguration) {
-        return switch (clientConfiguration.getProtocol()) {
-            case TCP -> createReconnectingTcpClient(clientConfiguration);
-            case SSH -> createReconnectingSshClient(clientConfiguration);
-            case TLS -> createReconnectingTlsClient(clientConfiguration);
-        };
-    }
-
     private Future<NetconfClientSession> createTcpClient(final NetconfClientConfiguration currentConfiguration) {
         LOG.debug("Creating TCP client with configuration: {}", currentConfiguration);
-        return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+        return super.createClient(currentConfiguration.getAddress(),
             (ch, promise) -> new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration),
                         currentConfiguration.getSessionListener()).initialize(ch, promise));
     }
 
-    private ReconnectFuture createReconnectingTcpClient(
-            final NetconfReconnectingClientConfiguration currentConfiguration) {
-        LOG.debug("Creating reconnecting TCP client with configuration: {}", currentConfiguration);
-        final TcpClientChannelInitializer init =
-                new TcpClientChannelInitializer(getNegotiatorFactory(currentConfiguration),
-                currentConfiguration.getSessionListener());
-
-        return super.createReconnectingClient(currentConfiguration.getAddress(),
-                currentConfiguration.getConnectStrategyFactory(), init::initialize);
-    }
-
     private Future<NetconfClientSession> createSshClient(final NetconfClientConfiguration currentConfiguration) {
         LOG.debug("Creating SSH client with configuration: {}", currentConfiguration);
-        return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+        return super.createClient(currentConfiguration.getAddress(),
             (ch, sessionPromise) -> new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
                         getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener(),
                         currentConfiguration.getSshClient(), currentConfiguration.getName())
                     .initialize(ch, sessionPromise));
     }
 
-    private ReconnectFuture createReconnectingSshClient(
-            final NetconfReconnectingClientConfiguration currentConfiguration) {
-        LOG.debug("Creating reconnecting SSH client with configuration: {}", currentConfiguration);
-        final SshClientChannelInitializer init = new SshClientChannelInitializer(currentConfiguration.getAuthHandler(),
-                getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener(),
-                currentConfiguration.getSshClient(), currentConfiguration.getName());
-
-        return super.createReconnectingClient(currentConfiguration.getAddress(),
-                currentConfiguration.getConnectStrategyFactory(), init::initialize);
-    }
-
     private Future<NetconfClientSession> createTlsClient(final NetconfClientConfiguration currentConfiguration) {
         LOG.debug("Creating TLS client with configuration: {}", currentConfiguration);
-        return super.createClient(currentConfiguration.getAddress(), currentConfiguration.getReconnectStrategy(),
+        return super.createClient(currentConfiguration.getAddress(),
             (ch, sessionPromise) -> new TlsClientChannelInitializer(currentConfiguration.getSslHandlerFactory(),
                     getNegotiatorFactory(currentConfiguration), currentConfiguration.getSessionListener())
                     .initialize(ch, sessionPromise));
     }
 
-    private ReconnectFuture createReconnectingTlsClient(
-            final NetconfReconnectingClientConfiguration currentConfiguration) {
-        LOG.debug("Creating reconnecting TLS client with configuration: {}", currentConfiguration);
-        final TlsClientChannelInitializer init = new TlsClientChannelInitializer(
-                currentConfiguration.getSslHandlerFactory(), getNegotiatorFactory(currentConfiguration),
-                currentConfiguration.getSessionListener());
-
-        return super.createReconnectingClient(currentConfiguration.getAddress(),
-                currentConfiguration.getConnectStrategyFactory(), init::initialize);
-    }
-
     protected NetconfClientSessionNegotiatorFactory getNegotiatorFactory(final NetconfClientConfiguration cfg) {
         final List<Uri> odlHelloCapabilities = cfg.getOdlHelloCapabilities();
         if (odlHelloCapabilities == null || odlHelloCapabilities.isEmpty()) {
index 1a7338ce8ca27392446b6a2bc3208a42a73be5b2..0ceba3c00569ce8692e2b1f121b403fa0cf3da8e 100644 (file)
@@ -18,7 +18,6 @@ import org.checkerframework.checker.index.qual.NonNegative;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.SslHandlerFactory;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
@@ -35,8 +34,6 @@ public class NetconfClientConfiguration {
     private final NetconfHelloMessageAdditionalHeader additionalHeader;
     private final NetconfClientSessionListener sessionListener;
 
-    private final ReconnectStrategy reconnectStrategy;
-
     private final AuthenticationHandler authHandler;
     private final SslHandlerFactory sslHandlerFactory;
     private final NetconfSshClient sshClient;
@@ -49,7 +46,7 @@ public class NetconfClientConfiguration {
                                final Long connectionTimeoutMillis,
                                final NetconfHelloMessageAdditionalHeader additionalHeader,
                                final NetconfClientSessionListener sessionListener,
-                               final ReconnectStrategy reconnectStrategy, final AuthenticationHandler authHandler,
+                               final AuthenticationHandler authHandler,
                                final SslHandlerFactory sslHandlerFactory, final NetconfSshClient sshClient,
                                final List<Uri> odlHelloCapabilities, final @NonNegative int maximumIncomingChunkSize,
                                final String name) {
@@ -58,7 +55,6 @@ public class NetconfClientConfiguration {
         this.additionalHeader = additionalHeader;
         this.sessionListener = sessionListener;
         clientProtocol = protocol;
-        this.reconnectStrategy = reconnectStrategy;
         this.authHandler = authHandler;
         this.sslHandlerFactory = sslHandlerFactory;
         this.sshClient = sshClient;
@@ -88,11 +84,6 @@ public class NetconfClientConfiguration {
         return sessionListener;
     }
 
-    @Deprecated(forRemoval = true)
-    public final ReconnectStrategy getReconnectStrategy() {
-        return reconnectStrategy;
-    }
-
     public final AuthenticationHandler getAuthHandler() {
         return authHandler;
     }
@@ -148,7 +139,6 @@ public class NetconfClientConfiguration {
         requireNonNull(clientProtocol, "clientProtocol");
         requireNonNull(connectionTimeoutMillis, "connectionTimeoutMillis");
         requireNonNull(sessionListener, "sessionListener");
-        requireNonNull(reconnectStrategy, "reconnectStrategy");
     }
 
     @Override
@@ -162,7 +152,6 @@ public class NetconfClientConfiguration {
                 .add("connectionTimeoutMillis", connectionTimeoutMillis)
                 .add("additionalHeader", additionalHeader)
                 .add("sessionListener", sessionListener)
-                .add("reconnectStrategy", reconnectStrategy)
                 .add("clientProtocol", clientProtocol)
                 .add("authHandler", authHandler)
                 .add("sslHandlerFactory", sslHandlerFactory);
index 16aa5c467aab85999ca7b5a2b04806e5e7f977b0..7aeb0e59756cf6429717da449a96286d9d005da2 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
 import org.opendaylight.netconf.client.SslHandlerFactory;
 import org.opendaylight.netconf.nettyutil.AbstractNetconfSessionNegotiator;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
@@ -31,7 +30,6 @@ public class NetconfClientConfigurationBuilder {
     private long connectionTimeoutMillis = DEFAULT_CONNECTION_TIMEOUT_MILLIS;
     private NetconfHelloMessageAdditionalHeader additionalHeader;
     private NetconfClientSessionListener sessionListener;
-    private ReconnectStrategy reconnectStrategy;
     private AuthenticationHandler authHandler;
     private NetconfClientConfiguration.NetconfClientProtocol clientProtocol = DEFAULT_CLIENT_PROTOCOL;
     private SslHandlerFactory sslHandlerFactory;
@@ -80,12 +78,6 @@ public class NetconfClientConfigurationBuilder {
         return this;
     }
 
-    @SuppressWarnings("checkstyle:hiddenField")
-    public NetconfClientConfigurationBuilder withReconnectStrategy(final ReconnectStrategy reconnectStrategy) {
-        this.reconnectStrategy = reconnectStrategy;
-        return this;
-    }
-
     @SuppressWarnings("checkstyle:hiddenField")
     public NetconfClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
         this.authHandler = authHandler;
@@ -140,10 +132,6 @@ public class NetconfClientConfigurationBuilder {
         return sessionListener;
     }
 
-    final ReconnectStrategy getReconnectStrategy() {
-        return reconnectStrategy;
-    }
-
     final AuthenticationHandler getAuthHandler() {
         return authHandler;
     }
@@ -174,7 +162,7 @@ public class NetconfClientConfigurationBuilder {
 
     public NetconfClientConfiguration build() {
         return new NetconfClientConfiguration(clientProtocol, address, connectionTimeoutMillis, additionalHeader,
-                sessionListener, reconnectStrategy, authHandler, sslHandlerFactory, sshClient, odlHelloCapabilities,
+                sessionListener, authHandler, sslHandlerFactory, sshClient, odlHelloCapabilities,
                 maximumIncomingChunkSize, name);
     }
 }
diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java
deleted file mode 100644 (file)
index 1612b50..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.client.conf;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.MoreObjects.ToStringHelper;
-import java.net.InetSocketAddress;
-import java.util.List;
-import org.checkerframework.checker.index.qual.NonNegative;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.client.SslHandlerFactory;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
-
-public final class NetconfReconnectingClientConfiguration extends NetconfClientConfiguration {
-    private final ReconnectStrategyFactory connectStrategyFactory;
-
-    NetconfReconnectingClientConfiguration(final NetconfClientProtocol clientProtocol, final InetSocketAddress address,
-                                           final Long connectionTimeoutMillis,
-                                           final NetconfHelloMessageAdditionalHeader additionalHeader,
-                                           final NetconfClientSessionListener sessionListener,
-                                           final ReconnectStrategy reconnectStrategy,
-                                           final ReconnectStrategyFactory connectStrategyFactory,
-                                           final AuthenticationHandler authHandler,
-                                           final SslHandlerFactory sslHandlerFactory,
-                                           final NetconfSshClient sshClient,
-                                           final List<Uri> odlHelloCapabilities,
-                                           final @NonNegative int maximumIncomingChunkSize,
-                                           final String name) {
-        super(clientProtocol, address, connectionTimeoutMillis, additionalHeader, sessionListener, reconnectStrategy,
-                authHandler, sslHandlerFactory, sshClient, odlHelloCapabilities, maximumIncomingChunkSize, name);
-        this.connectStrategyFactory = connectStrategyFactory;
-        validateReconnectConfiguration();
-    }
-
-    public ReconnectStrategyFactory getConnectStrategyFactory() {
-        return connectStrategyFactory;
-    }
-
-    private void validateReconnectConfiguration() {
-        requireNonNull(connectStrategyFactory);
-    }
-
-    @Override
-    protected ToStringHelper buildToStringHelper() {
-        return super.buildToStringHelper().add("connectStrategyFactory", connectStrategyFactory);
-    }
-}
diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java
deleted file mode 100644 (file)
index a42d5f2..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.client.conf;
-
-import java.net.InetSocketAddress;
-import java.util.List;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.netconf.client.NetconfClientSessionListener;
-import org.opendaylight.netconf.client.SslHandlerFactory;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-import org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
-
-public final class NetconfReconnectingClientConfigurationBuilder extends NetconfClientConfigurationBuilder {
-
-    private ReconnectStrategyFactory connectStrategyFactory;
-
-    private NetconfReconnectingClientConfigurationBuilder() {
-    }
-
-    public static NetconfReconnectingClientConfigurationBuilder create() {
-        return new NetconfReconnectingClientConfigurationBuilder();
-    }
-
-    @SuppressWarnings("checkstyle:hiddenField")
-    public NetconfReconnectingClientConfigurationBuilder withConnectStrategyFactory(
-            final ReconnectStrategyFactory connectStrategyFactory) {
-        this.connectStrategyFactory = connectStrategyFactory;
-        return this;
-    }
-
-    @Override
-    public NetconfReconnectingClientConfiguration build() {
-        return new NetconfReconnectingClientConfiguration(getProtocol(), getAddress(), getConnectionTimeoutMillis(),
-                getAdditionalHeader(), getSessionListener(), getReconnectStrategy(), connectStrategyFactory,
-                getAuthHandler(), getSslHandlerFactory(), getSshClient(), getOdlHelloCapabilities(),
-                getMaximumIncomingChunkSize(), getName());
-    }
-
-    // Override setter methods to return subtype
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withAddress(final InetSocketAddress address) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withAddress(address);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withConnectionTimeoutMillis(
-            final long connectionTimeoutMillis) {
-        return (NetconfReconnectingClientConfigurationBuilder)
-                super.withConnectionTimeoutMillis(connectionTimeoutMillis);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withAdditionalHeader(
-            final NetconfHelloMessageAdditionalHeader additionalHeader) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withAdditionalHeader(additionalHeader);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withSessionListener(
-            final NetconfClientSessionListener sessionListener) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withSessionListener(sessionListener);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withReconnectStrategy(
-            final ReconnectStrategy reconnectStrategy) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withReconnectStrategy(reconnectStrategy);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withAuthHandler(final AuthenticationHandler authHandler) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withAuthHandler(authHandler);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withProtocol(
-            final NetconfClientConfiguration.NetconfClientProtocol clientProtocol) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withProtocol(clientProtocol);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withSslHandlerFactory(
-            final SslHandlerFactory sslHandlerFactory) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withSslHandlerFactory(sslHandlerFactory);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withSshClient(
-        final NetconfSshClient sshClient) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withSshClient(sshClient);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withName(final String name) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withName(name);
-    }
-
-    @Override
-    public NetconfReconnectingClientConfigurationBuilder withOdlHelloCapabilities(
-            final List<Uri> odlHelloCapabilities) {
-        return (NetconfReconnectingClientConfigurationBuilder) super.withOdlHelloCapabilities(odlHelloCapabilities);
-    }
-}
index 46b2bfd38cb36f1cc0794058d43e09b36faca847..033bc4b8b9a1c73274c96e033028d0bf1e8c707d 100644 (file)
@@ -5,18 +5,17 @@
  * 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.client;
 
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
 import java.net.InetSocketAddress;
 import java.util.Optional;
-import org.junit.Assert;
 import org.junit.Test;
-import org.mockito.Mockito;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 
 public class NetconfClientConfigurationTest {
@@ -27,41 +26,36 @@ public class NetconfClientConfigurationTest {
                 new NetconfHelloMessageAdditionalHeader("a", "host", "port", "trans", "id");
         NetconfClientSessionListener listener = new SimpleNetconfClientSessionListener();
         InetSocketAddress address = InetSocketAddress.createUnresolved("host", 830);
-        ReconnectStrategy strategy = Mockito.mock(ReconnectStrategy.class);
-        AuthenticationHandler handler = Mockito.mock(AuthenticationHandler.class);
+        AuthenticationHandler handler = mock(AuthenticationHandler.class);
         NetconfClientConfiguration cfg = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
                 .withAddress(address)
                 .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(strategy)
                 .withAdditionalHeader(header)
                 .withSessionListener(listener)
                 .withAuthHandler(handler).build();
 
-        Assert.assertEquals(timeout, cfg.getConnectionTimeoutMillis());
-        Assert.assertEquals(Optional.of(header), cfg.getAdditionalHeader());
-        Assert.assertEquals(listener, cfg.getSessionListener());
-        Assert.assertEquals(handler, cfg.getAuthHandler());
-        Assert.assertEquals(strategy, cfg.getReconnectStrategy());
-        Assert.assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, cfg.getProtocol());
-        Assert.assertEquals(address, cfg.getAddress());
+        assertEquals(timeout, cfg.getConnectionTimeoutMillis());
+        assertEquals(Optional.of(header), cfg.getAdditionalHeader());
+        assertEquals(listener, cfg.getSessionListener());
+        assertEquals(handler, cfg.getAuthHandler());
+        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, cfg.getProtocol());
+        assertEquals(address, cfg.getAddress());
 
-        SslHandlerFactory sslHandlerFactory = Mockito.mock(SslHandlerFactory.class);
+        SslHandlerFactory sslHandlerFactory = mock(SslHandlerFactory.class);
         NetconfClientConfiguration cfg2 = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS)
                 .withAddress(address)
                 .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(strategy)
                 .withAdditionalHeader(header)
                 .withSessionListener(listener)
                 .withSslHandlerFactory(sslHandlerFactory).build();
 
-        Assert.assertEquals(timeout, cfg2.getConnectionTimeoutMillis());
-        Assert.assertEquals(Optional.of(header), cfg2.getAdditionalHeader());
-        Assert.assertEquals(listener, cfg2.getSessionListener());
-        Assert.assertEquals(sslHandlerFactory, cfg2.getSslHandlerFactory());
-        Assert.assertEquals(strategy, cfg2.getReconnectStrategy());
-        Assert.assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, cfg2.getProtocol());
-        Assert.assertEquals(address, cfg2.getAddress());
+        assertEquals(timeout, cfg2.getConnectionTimeoutMillis());
+        assertEquals(Optional.of(header), cfg2.getAdditionalHeader());
+        assertEquals(listener, cfg2.getSessionListener());
+        assertEquals(sslHandlerFactory, cfg2.getSslHandlerFactory());
+        assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, cfg2.getProtocol());
+        assertEquals(address, cfg2.getAddress());
     }
 }
index 62a2b33eb9c81299c6f289af2ca7d1bb89beebbc..40368370d9eddc62f05e7d7fbb5a031acee8ab91 100644 (file)
@@ -25,11 +25,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.ReconnectFuture;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
+import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 
 public class NetconfClientDispatcherImplTest {
@@ -56,42 +52,32 @@ public class NetconfClientDispatcherImplTest {
                 new NetconfHelloMessageAdditionalHeader("a", "host", "port", "trans", "id");
         NetconfClientSessionListener listener = new SimpleNetconfClientSessionListener();
         InetSocketAddress address = InetSocketAddress.createUnresolved("host", 830);
-        ReconnectStrategyFactory reconnectStrategyFactory = Mockito.mock(ReconnectStrategyFactory.class);
         AuthenticationHandler handler = Mockito.mock(AuthenticationHandler.class);
-        ReconnectStrategy reconnect = Mockito.mock(ReconnectStrategy.class);
 
-        doReturn(5).when(reconnect).getConnectTimeout();
-        doReturn("").when(reconnect).toString();
         doReturn("").when(handler).toString();
-        doReturn("").when(reconnectStrategyFactory).toString();
-        doReturn(reconnect).when(reconnectStrategyFactory).createReconnectStrategy();
 
-        NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
+        var cfg = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
                 .withAddress(address)
                 .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(reconnect)
                 .withAdditionalHeader(header)
                 .withSessionListener(listener)
-                .withConnectStrategyFactory(reconnectStrategyFactory)
                 .withAuthHandler(handler).build();
 
-        NetconfReconnectingClientConfiguration cfg2 = NetconfReconnectingClientConfigurationBuilder.create()
+        var cfg2 = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP)
                 .withAddress(address)
                 .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(reconnect)
                 .withAdditionalHeader(header)
                 .withSessionListener(listener)
-                .withConnectStrategyFactory(reconnectStrategyFactory)
                 .withAuthHandler(handler).build();
 
         NetconfClientDispatcherImpl dispatcher = new NetconfClientDispatcherImpl(bossGroup, workerGroup, timer);
         Future<NetconfClientSession> sshSession = dispatcher.createClient(cfg);
         Future<NetconfClientSession> tcpSession = dispatcher.createClient(cfg2);
 
-        ReconnectFuture sshReconn = dispatcher.createReconnectingClient(cfg);
-        final ReconnectFuture tcpReconn = dispatcher.createReconnectingClient(cfg2);
+        var sshReconn = dispatcher.createClient(cfg);
+        final var tcpReconn = dispatcher.createClient(cfg2);
 
         assertNotNull(sshSession);
         assertNotNull(tcpSession);
@@ -99,18 +85,16 @@ public class NetconfClientDispatcherImplTest {
         assertNotNull(tcpReconn);
 
         SslHandlerFactory sslHandlerFactory = Mockito.mock(SslHandlerFactory.class);
-        NetconfReconnectingClientConfiguration cfg3 = NetconfReconnectingClientConfigurationBuilder.create()
+        var cfg3 = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS)
                 .withAddress(address)
                 .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(reconnect)
                 .withAdditionalHeader(header)
                 .withSessionListener(listener)
-                .withConnectStrategyFactory(reconnectStrategyFactory)
                 .withSslHandlerFactory(sslHandlerFactory).build();
 
         Future<NetconfClientSession> tlsSession = dispatcher.createClient(cfg3);
-        ReconnectFuture tlsReconn = dispatcher.createReconnectingClient(cfg3);
+        var tlsReconn = dispatcher.createClient(cfg3);
 
         assertNotNull(tlsSession);
         assertNotNull(tlsReconn);
diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfReconnectingClientConfigurationTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfReconnectingClientConfigurationTest.java
deleted file mode 100644 (file)
index ec09f88..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. 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.client;
-
-import java.net.InetSocketAddress;
-import java.util.Optional;
-import org.junit.Assert;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
-import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
-import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
-import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
-
-public class NetconfReconnectingClientConfigurationTest {
-    @Test
-    public void testNetconfReconnectingClientConfiguration() throws Exception {
-        Long timeout = 200L;
-        NetconfHelloMessageAdditionalHeader header =
-                new NetconfHelloMessageAdditionalHeader("a", "host", "port", "trans", "id");
-        NetconfClientSessionListener listener = new SimpleNetconfClientSessionListener();
-        InetSocketAddress address = InetSocketAddress.createUnresolved("host", 830);
-        ReconnectStrategyFactory strategy = Mockito.mock(ReconnectStrategyFactory.class);
-        AuthenticationHandler handler = Mockito.mock(AuthenticationHandler.class);
-        ReconnectStrategy reconnect = Mockito.mock(ReconnectStrategy.class);
-
-        NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
-                .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
-                .withAddress(address)
-                .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(reconnect)
-                .withAdditionalHeader(header)
-                .withSessionListener(listener)
-                .withConnectStrategyFactory(strategy)
-                .withAuthHandler(handler).build();
-
-        Assert.assertEquals(timeout, cfg.getConnectionTimeoutMillis());
-        Assert.assertEquals(Optional.of(header), cfg.getAdditionalHeader());
-        Assert.assertEquals(listener, cfg.getSessionListener());
-        Assert.assertEquals(handler, cfg.getAuthHandler());
-        Assert.assertEquals(strategy, cfg.getConnectStrategyFactory());
-        Assert.assertEquals(NetconfClientConfiguration.NetconfClientProtocol.SSH, cfg.getProtocol());
-        Assert.assertEquals(address, cfg.getAddress());
-        Assert.assertEquals(reconnect, cfg.getReconnectStrategy());
-
-        SslHandlerFactory sslHandlerFactory = Mockito.mock(SslHandlerFactory.class);
-        NetconfReconnectingClientConfiguration cfg2 = NetconfReconnectingClientConfigurationBuilder.create()
-                .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS)
-                .withAddress(address)
-                .withConnectionTimeoutMillis(timeout)
-                .withReconnectStrategy(reconnect)
-                .withAdditionalHeader(header)
-                .withSessionListener(listener)
-                .withConnectStrategyFactory(strategy)
-                .withSslHandlerFactory(sslHandlerFactory).build();
-
-        Assert.assertEquals(timeout, cfg2.getConnectionTimeoutMillis());
-        Assert.assertEquals(Optional.of(header), cfg2.getAdditionalHeader());
-        Assert.assertEquals(listener, cfg2.getSessionListener());
-        Assert.assertEquals(sslHandlerFactory, cfg2.getSslHandlerFactory());
-        Assert.assertEquals(strategy, cfg2.getConnectStrategyFactory());
-        Assert.assertEquals(NetconfClientConfiguration.NetconfClientProtocol.TLS, cfg2.getProtocol());
-        Assert.assertEquals(address, cfg2.getAddress());
-        Assert.assertEquals(reconnect, cfg2.getReconnectStrategy());
-    }
-}
index 339c7e7dd74d2c6dd74c2f5cf710e705cdb15984..6d6916aa5b73c61560e33266ae30cb3491ad42cb 100644 (file)
@@ -13,7 +13,6 @@ import com.google.common.collect.Sets;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetAddress;
@@ -30,7 +29,6 @@ import org.opendaylight.netconf.api.NetconfMessage;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration.NetconfClientProtocol;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.NeverReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
@@ -117,14 +115,11 @@ public class TestingNetconfClient implements Closeable {
     private static NetconfClientConfiguration getClientConfig(final String host, final int port, final boolean ssh,
             final Optional<? extends AuthenticationHandler> maybeAuthHandler) throws UnknownHostException {
         InetSocketAddress netconfAddress = new InetSocketAddress(InetAddress.getByName(host), port);
-        final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
-        b.withAddress(netconfAddress);
-        b.withSessionListener(new SimpleNetconfClientSessionListener());
-        b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS));
+        final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create()
+            .withAddress(netconfAddress)
+            .withSessionListener(new SimpleNetconfClientSessionListener());
         if (ssh) {
-            b.withProtocol(NetconfClientProtocol.SSH);
-            b.withAuthHandler(maybeAuthHandler.orElseThrow());
+            b.withProtocol(NetconfClientProtocol.SSH).withAuthHandler(maybeAuthHandler.orElseThrow());
         } else {
             b.withProtocol(NetconfClientProtocol.TCP);
         }
index 983bca0a2d504c463bf54f05c2adf41e682c6495..9d1c1da3274fea14e0cd60c976355a46488f7348 100644 (file)
@@ -20,7 +20,6 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
-import io.netty.util.concurrent.GlobalEventExecutor;
 import java.io.DataOutputStream;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -55,7 +54,6 @@ import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener;
 import org.opendaylight.netconf.client.TestingNetconfClient;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.NeverReconnectStrategy;
 import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
 import org.opendaylight.netconf.server.api.monitoring.Capability;
@@ -378,14 +376,12 @@ public class ConcurrentClientsTest {
         }
 
         private NetconfClientConfiguration getClientConfig() {
-            final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
-            b.withAddress(NETCONF_ADDRESS);
-            b.withAdditionalHeader(new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp",
-                    "client"));
-            b.withSessionListener(new SimpleNetconfClientSessionListener());
-            b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE,
-                    NetconfClientConfigurationBuilder.DEFAULT_CONNECTION_TIMEOUT_MILLIS));
-            return b.build();
+            return NetconfClientConfigurationBuilder.create()
+                .withAddress(NETCONF_ADDRESS)
+                .withAdditionalHeader(
+                    new NetconfHelloMessageAdditionalHeader("uname", "10.10.10.1", "830", "tcp", "client"))
+                .withSessionListener(new SimpleNetconfClientSessionListener())
+                .build();
         }
     }
 }