From 805fa94043a3655400415228f01b1efef554c921 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 3 Jul 2023 10:32:23 +0200 Subject: [PATCH] Rework NETCONF client reconnection 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 --- .../mount/CallHomeMountDispatcher.java | 7 - .../callhome/mount/SingleReconnectFuture.java | 53 ---- .../mount/CallHomeMountDispatcherTest.java | 5 +- .../impl/NetconfTopologyImplTest.java | 31 +- .../impl/MountPointEndToEndTest.java | 6 +- .../topology/spi/AbstractNetconfTopology.java | 200 ++---------- .../topology/spi/NetconfConnectorDTO.java | 45 --- .../topology/spi/NetconfNodeHandler.java | 290 ++++++++++++++++++ .../nettyutil/AbstractNetconfDispatcher.java | 37 +-- .../nettyutil/NetconfSessionPromise.java | 52 +--- .../nettyutil/NeverReconnectStrategy.java | 44 --- .../netconf/nettyutil/ReconnectFuture.java | 28 -- .../ReconnectImmediatelyStrategy.java | 49 --- .../netconf/nettyutil/ReconnectPromise.java | 124 -------- .../netconf/nettyutil/ReconnectStrategy.java | 55 ---- .../nettyutil/ReconnectStrategyFactory.java | 24 -- .../nettyutil/TimedReconnectStrategy.java | 183 ----------- .../TimedReconnectStrategyFactory.java | 38 --- .../client/stress/StressClientCallable.java | 20 +- .../netconf/test/tool/TestToolTest.java | 5 - .../mdsal/NetconfDeviceCommunicator.java | 55 ---- .../mdsal/NetconfDeviceCommunicatorTest.java | 73 +---- .../client/NetconfClientDispatcher.java | 5 - .../client/NetconfClientDispatcherImpl.java | 50 +-- .../conf/NetconfClientConfiguration.java | 13 +- .../NetconfClientConfigurationBuilder.java | 14 +- ...etconfReconnectingClientConfiguration.java | 58 ---- ...econnectingClientConfigurationBuilder.java | 112 ------- .../NetconfClientConfigurationTest.java | 40 +-- .../NetconfClientDispatcherImplTest.java | 30 +- ...nfReconnectingClientConfigurationTest.java | 75 ----- .../netconf/client/TestingNetconfClient.java | 13 +- .../netconf/server/ConcurrentClientsTest.java | 16 +- 33 files changed, 402 insertions(+), 1448 deletions(-) delete mode 100644 apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/SingleReconnectFuture.java delete mode 100644 apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfConnectorDTO.java create mode 100644 apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NeverReconnectStrategy.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectFuture.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectImmediatelyStrategy.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectPromise.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategy.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategyFactory.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategy.java delete mode 100644 netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategyFactory.java delete mode 100644 protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java delete mode 100644 protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java delete mode 100644 protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfReconnectingClientConfigurationTest.java diff --git a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java index 86ae0725c2..0164038af9 100644 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java +++ b/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java @@ -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 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 index 121235dfa9..0000000000 --- a/apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/SingleReconnectFuture.java +++ /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 implements ReconnectFuture { - private final Future sessionFuture; - - SingleReconnectFuture(final EventExecutor eventExecutor, final Future 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; - } -} diff --git a/apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java b/apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java index b4c8a659fd..6fe9cda6f2 100644 --- a/apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java +++ b/apps/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java @@ -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 diff --git a/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java b/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java index 7c37b77e0f..5c9b3b01dd 100644 --- a/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java +++ b/apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java @@ -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()); } diff --git a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java index d4d473166a..4897482aab 100644 --- a/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java +++ b/apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java @@ -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"); } diff --git a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java index fc7d897c23..883ad18de0 100644 --- a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java +++ b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java @@ -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 activeConnectors = new HashMap<>(); + private final HashMap 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 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 device; - final List> 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> 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> 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 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 index 7da4c95695..0000000000 --- a/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfConnectorDTO.java +++ /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> yanglibRegistrations; - private final @NonNull NetconfDeviceCommunicator communicator; - private final @NonNull RemoteDeviceHandler facade; - - NetconfConnectorDTO(final NetconfDeviceCommunicator communicator, final RemoteDeviceHandler facade, - final List> 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 index 0000000000..84dddf9825 --- /dev/null +++ b/apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java @@ -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> 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 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> 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>(); + 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 diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfDispatcher.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfDispatcher.java index dbe6d830e1..cdfec0b287 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfDispatcher.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/AbstractNetconfDispatcher.java @@ -136,15 +136,14 @@ public abstract class AbstractNetconfDispatcher createClient(final InetSocketAddress address, final ReconnectStrategy strategy, - final PipelineInitializer initializer) { + protected Future createClient(final InetSocketAddress address, final PipelineInitializer initializer) { final Bootstrap b = new Bootstrap(); - final NetconfSessionPromise p = new NetconfSessionPromise<>(executor, address, strategy, b); + final NetconfSessionPromise p = new NetconfSessionPromise<>(executor, address, b); b.option(ChannelOption.SO_KEEPALIVE, true).handler( new ChannelInitializer() { @Override @@ -167,9 +166,9 @@ public abstract class AbstractNetconfDispatcher createClient(final InetSocketAddress address, final ReconnectStrategy strategy, - final Bootstrap bootstrap, final PipelineInitializer initializer) { - final NetconfSessionPromise p = new NetconfSessionPromise<>(executor, address, strategy, bootstrap); + protected Future createClient(final InetSocketAddress address, final Bootstrap bootstrap, + final PipelineInitializer initializer) { + final NetconfSessionPromise p = new NetconfSessionPromise<>(executor, address, bootstrap); bootstrap.handler( new ChannelInitializer() { @@ -184,30 +183,6 @@ public abstract class AbstractNetconfDispatcher initializer) { - final Bootstrap b = new Bootstrap(); - - final ReconnectPromise 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() diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionPromise.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionPromise.java index 4a8fb7f88c..677f30f37f 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionPromise.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionPromise.java @@ -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 extends DefaultPromise { 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 extends DefaultPromi @Override public synchronized Promise 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 extends DefaultPromi } LOG.debug("Attempt to connect to {} failed", address, cf.cause()); - - final Future 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 index f3a46ba3af..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NeverReconnectStrategy.java +++ /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 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 index 62fc049d2f..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectFuture.java +++ /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 { - /** - * 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 index da0c5e5fc1..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectImmediatelyStrategy.java +++ /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 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 index 4537fcdc59..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectPromise.java +++ /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> - extends DefaultPromise implements ReconnectFuture { - private static final Logger LOG = LoggerFactory.getLogger(ReconnectPromise.class); - - private final AbstractNetconfDispatcher dispatcher; - private final InetSocketAddress address; - private final ReconnectStrategyFactory strategyFactory; - private final Bootstrap bootstrap; - private final PipelineInitializer initializer; - private final Promise firstSessionFuture; - - @GuardedBy("this") - private Future pending; - - ReconnectPromise(final EventExecutor executor, final AbstractNetconfDispatcher dispatcher, - final InetSocketAddress address, final ReconnectStrategyFactory connectStrategyFactory, - final Bootstrap bootstrap, final PipelineInitializer 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 index 55e6b03828..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategy.java +++ /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. - * - *

- * 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 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 index 275e9b926e..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/ReconnectStrategyFactory.java +++ /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 index 895ebb22a0..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategy.java +++ /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. - * - *

- * This strategy continues to schedule reconnect attempts, each having to complete in a fixed time (connectTime). - * - *

- * 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 > 1). Maximum sleep time between attempts can be capped to a specific value - * (maxSleep). - * - *

- * The strategy can optionally give up based on two criteria: - * - *

- * A preset number of connection retries (maxAttempts) has been reached, or - * - *

- * 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. - * - *

- * 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 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 index bf26187e12..0000000000 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/TimedReconnectStrategyFactory.java +++ /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 diff --git a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClientCallable.java b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClientCallable.java index b295bbf2f7..0de06d9012 100644 --- a/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClientCallable.java +++ b/netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClientCallable.java @@ -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 { 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 { } }); } - 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(); } } diff --git a/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java b/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java index c2eaa8dcce..4e29072ad4 100644 --- a/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java +++ b/netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java @@ -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(); diff --git a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicator.java b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicator.java index 4e8e680a0a..5edf44fce0 100644 --- a/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicator.java +++ b/plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicator.java @@ -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 requests = new ArrayDeque<>(); private NetconfClientSession currentSession; - private final SettableFuture 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 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(); diff --git a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicatorTest.java b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicatorTest.java index 1f283eaa00..53989409ec 100644 --- a/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicatorTest.java +++ b/plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/NetconfDeviceCommunicatorTest.java @@ -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 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 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 = "" + String xmlStr = "" + "\n" + "protocol\n" + "operation-failed\n" diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcher.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcher.java index b1d2a12468..ed3b3c6dba 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcher.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcher.java @@ -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 createClient(NetconfClientConfiguration clientConfiguration); - - ReconnectFuture createReconnectingClient(NetconfReconnectingClientConfiguration clientConfiguration); } diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java index ef8fb66d57..33454c2dfd 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientDispatcherImpl.java @@ -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 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 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 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 odlHelloCapabilities = cfg.getOdlHelloCapabilities(); if (odlHelloCapabilities == null || odlHelloCapabilities.isEmpty()) { diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java index 1a7338ce8c..0ceba3c005 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfiguration.java @@ -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 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); diff --git a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java index 16aa5c467a..7aeb0e5975 100644 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java +++ b/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfClientConfigurationBuilder.java @@ -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 index 1612b50eb1..0000000000 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfiguration.java +++ /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 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 index a42d5f2cdd..0000000000 --- a/protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/conf/NetconfReconnectingClientConfigurationBuilder.java +++ /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 odlHelloCapabilities) { - return (NetconfReconnectingClientConfigurationBuilder) super.withOdlHelloCapabilities(odlHelloCapabilities); - } -} diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientConfigurationTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientConfigurationTest.java index 46b2bfd38c..033bc4b8b9 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientConfigurationTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientConfigurationTest.java @@ -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()); } } diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientDispatcherImplTest.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientDispatcherImplTest.java index 62a2b33eb9..40368370d9 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientDispatcherImplTest.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientDispatcherImplTest.java @@ -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 sshSession = dispatcher.createClient(cfg); Future 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 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 index ec09f88efa..0000000000 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfReconnectingClientConfigurationTest.java +++ /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()); - } -} diff --git a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/TestingNetconfClient.java b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/TestingNetconfClient.java index 339c7e7dd7..6d6916aa5b 100644 --- a/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/TestingNetconfClient.java +++ b/protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/TestingNetconfClient.java @@ -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 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); } diff --git a/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java b/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java index 983bca0a2d..9d1c1da327 100644 --- a/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java +++ b/protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java @@ -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(); } } } -- 2.36.6