Introduce NetconfTimer 37/110037/8
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 27 Jan 2024 15:44:55 +0000 (16:44 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 27 Jan 2024 18:56:30 +0000 (19:56 +0100)
The wiring of a global timer is not quite what we want, as it makes
tracking down where and how it is used quite hard.

Add an explicit NetconfTimer interface and a default implementation to
provide indirection in from on the Netty timer.

This has the benefit of reigning in the lifecycle of the timer, so we
actually end up sharing it across components properly.

JIRA: NETCONF-590
Change-Id: Ib58c9f5668ec859d68432116fe63f954f6eae08e
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
50 files changed:
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountService.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/IetfZeroTouchCallHomeServerProvider.java
apps/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/tls/NetconfCallHomeTlsService.java
apps/netconf-nb/src/main/java/org/opendaylight/netconf/northbound/OSGiNetconfServer.java
apps/netconf-topology-impl/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java
apps/netconf-topology-impl/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java
apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java
apps/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java
apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/MountPointEndToEndTest.java
apps/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/AbstractNetconfTopology.java
apps/netconf-topology/src/main/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandler.java
apps/netconf-topology/src/test/java/org/opendaylight/netconf/topology/spi/NetconfNodeHandlerTest.java
artifacts/pom.xml
features/odl-netconf-client/pom.xml
features/odl-netconf-client/src/main/feature/feature.xml [deleted file]
netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/CallHomeTransportChannelListener.java
netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServer.java
netconf/callhome-server/src/main/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServer.java
netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/ssh/CallHomeSshServerTest.java
netconf/callhome-server/src/test/java/org/opendaylight/netconf/callhome/server/tls/CallHomeTlsServerTest.java
netconf/netconf-netty-util/pom.xml
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/NetconfSessionNegotiator.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/AbstractNetconfSessionNegotiatorTest.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/Netconf539Test.java
netconf/netconf-netty-util/src/test/java/org/opendaylight/netconf/nettyutil/TestSessionNegotiator.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/NetconfDeviceSimulator.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/TesttoolNegotiationFactory.java
netconf/tools/netconf-testtool/src/main/java/org/opendaylight/netconf/test/tool/client/stress/StressClient.java
netconf/tools/netconf-testtool/src/test/java/org/opendaylight/netconf/test/tool/TestToolTest.java
plugins/netconf-client-mdsal/src/main/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacade.java
plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeResponseWaitingTest.java
plugins/netconf-client-mdsal/src/test/java/org/opendaylight/netconf/client/mdsal/spi/KeepaliveSalFacadeTest.java
protocol/netconf-client/pom.xml
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientFactoryImpl.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java
protocol/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactory.java
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientFactoryImplTest.java
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorFactoryTest.java
protocol/netconf-client/src/test/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiatorTest.java
protocol/netconf-common/pom.xml [new file with mode: 0644]
protocol/netconf-common/src/main/java/module-info.java [new file with mode: 0644]
protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java [new file with mode: 0644]
protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java [new file with mode: 0644]
protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java [new file with mode: 0644]
protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiator.java
protocol/netconf-server/src/main/java/org/opendaylight/netconf/server/NetconfServerSessionNegotiatorFactory.java
protocol/netconf-server/src/test/java/org/opendaylight/netconf/server/ConcurrentClientsTest.java
protocol/pom.xml

index e1dddc02c9f3e6022525d4102639a59f208c1670..cf2af212420e1a05b676069679193af96d82410e 100644 (file)
@@ -11,7 +11,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 import io.netty.channel.Channel;
-import io.netty.util.Timer;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.util.Map;
@@ -35,6 +34,7 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.shaded.sshd.client.session.ClientSession;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
 import org.opendaylight.netconf.topology.spi.NetconfNodeHandler;
@@ -119,7 +119,7 @@ public final class CallHomeMountService implements AutoCloseable {
     @Activate
     @Inject
     public CallHomeMountService(
-            final @Reference(target = "(type=global-timer)") Timer timer,
+            final @Reference NetconfTimer timer,
             final @Reference NetconfTopologySchemaAssembler schemaAssembler,
             final @Reference SchemaResourceManager schemaRepositoryProvider,
             final @Reference BaseNetconfSchemas baseSchemas,
@@ -130,7 +130,7 @@ public final class CallHomeMountService implements AutoCloseable {
             dataBroker, mountService, deviceActionFactory);
     }
 
-    public CallHomeMountService(final String topologyId, final Timer timer,
+    public CallHomeMountService(final String topologyId, final NetconfTimer timer,
             final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider,
             final BaseNetconfSchemas baseSchemas, final DataBroker dataBroker, final DOMMountPointService mountService,
             final DeviceActionFactory deviceActionFactory) {
index d3dceb1bf3cd169e1dcf265b161da8e5ff6f8cb1..2606467a6e7f3b08495f46103561f1a6752de914 100644 (file)
@@ -7,13 +7,13 @@
  */
 package org.opendaylight.netconf.callhome.mount;
 
-import io.netty.util.Timer;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
 import org.opendaylight.netconf.topology.spi.NetconfTopologySchemaAssembler;
@@ -22,7 +22,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 
 // Non-final for mocking
 class CallHomeTopology extends AbstractNetconfTopology {
-    CallHomeTopology(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer,
+    CallHomeTopology(final String topologyId, final NetconfClientFactory clientFactory, final NetconfTimer timer,
             final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider,
             final DataBroker dataBroker, final DOMMountPointService mountPointService,
             final NetconfClientConfigurationBuilderFactory builderFactory, final BaseNetconfSchemas baseSchemas,
index 83ff5eb05cf0e9a1724cf1cb641d824c641195a1..89d05b64a4b8015f0265316f46f6b4993836d73a 100644 (file)
@@ -9,11 +9,14 @@ package org.opendaylight.netconf.callhome.mount;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Optional;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
 import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshAuthProvider;
 import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshServer;
+import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -44,6 +47,7 @@ public final class IetfZeroTouchCallHomeServerProvider implements AutoCloseable
     @Activate
     @Inject
     public IetfZeroTouchCallHomeServerProvider(
+            final @Reference NetconfTimer timer,
             final @Reference CallHomeMountService mountService,
             final @Reference CallHomeSshAuthProvider authProvider,
             final @Reference CallHomeStatusRecorder statusRecorder,
@@ -58,6 +62,8 @@ public final class IetfZeroTouchCallHomeServerProvider implements AutoCloseable
                 .withAuthProvider(authProvider)
                 .withStatusRecorder(statusRecorder)
                 .withSessionContextManager(mountService.createSshSessionContextManager())
+                .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), 10000L,
+                    NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
                 .build();
         } catch (UnknownHostException e) {
             throw new IllegalArgumentException("Invalid address", e);
index 7377e541176be1f9616fd3894024e289fc69b32e..9a8a3a076e81501bc4fa46cfcf8bdfa529041eaa 100644 (file)
@@ -9,12 +9,15 @@ package org.opendaylight.netconf.callhome.mount.tls;
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Optional;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.netconf.callhome.mount.CallHomeMountService;
 import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
 import org.opendaylight.netconf.callhome.server.tls.CallHomeTlsAuthProvider;
 import org.opendaylight.netconf.callhome.server.tls.CallHomeTlsServer;
+import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
@@ -52,6 +55,7 @@ public class NetconfCallHomeTlsService implements AutoCloseable {
     @Activate
     @Inject
     public NetconfCallHomeTlsService(
+            final @Reference NetconfTimer timer,
             final @Reference CallHomeMountService mountService,
             final @Reference CallHomeTlsAuthProvider authProvider,
             final @Reference CallHomeStatusRecorder statusRecorder,
@@ -68,6 +72,8 @@ public class NetconfCallHomeTlsService implements AutoCloseable {
                 .withStatusRecorder(statusRecorder)
                 .withSessionContextManager(
                     mountService.createTlsSessionContextManager(authProvider, statusRecorder))
+                .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(),
+                    configuration.timeoutMillis(), NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
                 .build();
         } catch (UnknownHostException e) {
             throw new IllegalArgumentException("invalid host", e);
index ee6271593eb2df923be15b38e70bae8040e2aee1..c4e39193209e78b8f68a4fab9d91891a465b628d 100644 (file)
@@ -10,8 +10,8 @@ package org.opendaylight.netconf.northbound;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
-import io.netty.util.Timer;
 import java.util.Map;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.netconf.server.ServerTransportInitializer;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
@@ -49,8 +49,7 @@ public final class OSGiNetconfServer {
             final ComponentFactory<DefaultNetconfMonitoringService> monitoringFactory,
             @Reference(target = "(type=mapper-aggregator-registry)")
             final NetconfOperationServiceFactory mapperAggregatorRegistry,
-            @Reference(target = "(type=global-timer)") final Timer timer,
-            @Reference final SessionIdProvider sessionIdProvider,
+            @Reference final NetconfTimer timer, @Reference final SessionIdProvider sessionIdProvider,
             final Configuration configuration) {
         mappers.onAddNetconfOperationServiceFactory(mapperAggregatorRegistry);
         monitoring = monitoringFactory.newInstance(FrameworkUtil.asDictionary(DefaultNetconfMonitoringService.props(
index f71cf9356ff80677cf2c4b8e7505127483b158bf..11dc3417ac59904f57ea21cd44813a72d1f48a0b 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.netconf.topology.impl;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import io.netty.util.Timer;
 import java.util.Collection;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
@@ -25,6 +24,7 @@ import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.spi.AbstractNetconfTopology;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
 import org.opendaylight.netconf.topology.spi.NetconfNodeUtils;
@@ -58,7 +58,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
     @Activate
     public NetconfTopologyImpl(
             @Reference(target = "(type=netconf-client-factory)") final NetconfClientFactory clientFactory,
-            @Reference(target = "(type=global-timer)") final Timer timer,
+            @Reference final NetconfTimer timer,
             @Reference final NetconfTopologySchemaAssembler schemaAssembler,
             @Reference final SchemaResourceManager schemaRepositoryProvider, @Reference final DataBroker dataBroker,
             @Reference final DOMMountPointService mountPointService,
@@ -72,7 +72,7 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
     }
 
     public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientclientFactory,
-            final Timer timer, final NetconfTopologySchemaAssembler schemaAssembler,
+            final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler,
             final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker,
             final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService,
             final NetconfClientConfigurationBuilderFactory builderFactory, final RpcProviderService rpcProviderService,
@@ -83,12 +83,12 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology
 
     @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR",
         justification = "DTCL registration of 'this'")
-    public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer,
-            final NetconfTopologySchemaAssembler schemaAssembler, final SchemaResourceManager schemaRepositoryProvider,
-            final DataBroker dataBroker, final DOMMountPointService mountPointService,
-            final AAAEncryptionService encryptionService, final NetconfClientConfigurationBuilderFactory builderFactory,
-            final RpcProviderService rpcProviderService, final BaseNetconfSchemas baseSchemas,
-            final DeviceActionFactory deviceActionFactory) {
+    public NetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory,
+            final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler,
+            final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker,
+            final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService,
+            final NetconfClientConfigurationBuilderFactory builderFactory, final RpcProviderService rpcProviderService,
+            final BaseNetconfSchemas baseSchemas, final DeviceActionFactory deviceActionFactory) {
         super(topologyId, clientFactory, timer, schemaAssembler, schemaRepositoryProvider, dataBroker,
             mountPointService, builderFactory, deviceActionFactory, baseSchemas);
 
index 2458c8593201c7854b115751d686cf5681fb23c8..117efbc2174cbd70c90ba750d3ec525dca29f9b1 100644 (file)
@@ -12,7 +12,6 @@ import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import io.netty.util.Timer;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.junit.jupiter.api.Test;
@@ -33,6 +32,7 @@ import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemas;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
 import org.opendaylight.netconf.topology.spi.NetconfTopologySchemaAssembler;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
@@ -66,7 +66,7 @@ class NetconfTopologyImplTest {
     @Mock
     private NetconfClientFactory mockedClientFactory;
     @Mock
-    private Timer mockedTimer;
+    private NetconfTimer mockedTimer;
     @Mock
     private SchemaResourceManager mockedResourceManager;
     @Mock
@@ -147,8 +147,8 @@ class NetconfTopologyImplTest {
     }
 
     private static class TestingNetconfTopologyImpl extends NetconfTopologyImpl {
-        TestingNetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory, final Timer timer,
-                final NetconfTopologySchemaAssembler schemaAssembler,
+        TestingNetconfTopologyImpl(final String topologyId, final NetconfClientFactory clientFactory,
+                final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler,
                 final SchemaResourceManager schemaRepositoryProvider, final DataBroker dataBroker,
                 final DOMMountPointService mountPointService, final AAAEncryptionService encryptionService,
                 final NetconfClientConfigurationBuilderFactory builderFactory,
index 77cf2d90813e582eee2149230757b48312ee01d8..145994deeb7413cd0e06e1cc2132eb7e525a1208 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.MoreExecutors;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import io.netty.util.Timer;
 import java.time.Duration;
 import java.util.Collection;
 import java.util.Map;
@@ -43,6 +42,7 @@ import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
@@ -95,7 +95,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
     private final BaseNetconfSchemas baseSchemas;
     private final DataBroker dataBroker;
     private final ClusterSingletonServiceProvider clusterSingletonServiceProvider;
-    private final Timer timer;
+    private final NetconfTimer timer;
     private final NetconfTopologySchemaAssembler schemaAssembler;
     private final ActorSystem actorSystem;
     private final NetconfClientFactory clientFactory;
@@ -113,7 +113,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
     public NetconfTopologyManager(@Reference final BaseNetconfSchemas baseSchemas,
             @Reference final DataBroker dataBroker,
             @Reference final ClusterSingletonServiceProvider clusterSingletonServiceProvider,
-            @Reference(target = "(type=global-timer)") final Timer timer,
+            @Reference final NetconfTimer timer,
             @Reference final NetconfTopologySchemaAssembler schemaAssembler,
             @Reference final ActorSystemProvider actorSystemProvider,
             @Reference(target = "(type=netconf-client-factory)") final NetconfClientFactory clientFactory,
@@ -132,7 +132,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
 
     @Inject
     public NetconfTopologyManager(final BaseNetconfSchemas baseSchemas, final DataBroker dataBroker,
-            final ClusterSingletonServiceProvider clusterSingletonServiceProvider, final Timer timer,
+            final ClusterSingletonServiceProvider clusterSingletonServiceProvider, final NetconfTimer timer,
             final NetconfTopologySchemaAssembler schemaAssembler, final ActorSystemProvider actorSystemProvider,
             final NetconfClientFactory clientFactory, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
@@ -147,7 +147,7 @@ public class NetconfTopologyManager implements ClusteredDataTreeChangeListener<N
     @SuppressFBWarnings(value = "MC_OVERRIDABLE_METHOD_CALL_IN_CONSTRUCTOR",
         justification = "Non-final for mocking, but we register for DTCL and that leaks 'this'")
     public NetconfTopologyManager(final BaseNetconfSchemas baseSchemas, final DataBroker dataBroker,
-            final ClusterSingletonServiceProvider clusterSingletonServiceProvider, final Timer timer,
+            final ClusterSingletonServiceProvider clusterSingletonServiceProvider, final NetconfTimer timer,
             final NetconfTopologySchemaAssembler schemaAssembler, final ActorSystem actorSystem,
             final NetconfClientFactory clientFactory, final DOMMountPointService mountPointService,
             final AAAEncryptionService encryptionService, final RpcProviderService rpcProviderService,
index e6ea772e2eb79ec0973de05aa25766308d2b2e18..e44ad70a961050cf5357940189fae9a65ba9e83a 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.netconf.topology.singleton.impl.utils;
 import static java.util.Objects.requireNonNull;
 
 import akka.actor.ActorSystem;
-import io.netty.util.Timer;
 import java.time.Duration;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.api.DataBroker;
@@ -18,6 +17,7 @@ import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvid
 import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.NetconfDevice;
 import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.spi.NetconfTopologySchemaAssembler;
 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;
@@ -27,7 +27,7 @@ public final class NetconfTopologySetup {
     private final DataBroker dataBroker;
     private final InstanceIdentifier<Node> instanceIdentifier;
     private final Node node;
-    private final Timer timer;
+    private final NetconfTimer timer;
     private final NetconfTopologySchemaAssembler schemaAssembler;
     private final ActorSystem actorSystem;
     private final NetconfClientFactory netconfClientFactory;
@@ -71,7 +71,7 @@ public final class NetconfTopologySetup {
         return schemaAssembler;
     }
 
-    public Timer getTimer() {
+    public NetconfTimer getTimer() {
         return timer;
     }
 
@@ -108,7 +108,7 @@ public final class NetconfTopologySetup {
         private DataBroker dataBroker;
         private InstanceIdentifier<Node> instanceIdentifier;
         private Node node;
-        private Timer timer;
+        private NetconfTimer timer;
         private NetconfTopologySchemaAssembler schemaAssembler;
         private ActorSystem actorSystem;
         private String topologyId;
@@ -171,11 +171,11 @@ public final class NetconfTopologySetup {
             return new NetconfTopologySetup(this);
         }
 
-        Timer getTimer() {
+        NetconfTimer getTimer() {
             return timer;
         }
 
-        public Builder setTimer(final Timer timer) {
+        public Builder setTimer(final NetconfTimer timer) {
             this.timer = requireNonNull(timer);
             return this;
         }
index ce76dc9c12281f2421bd4e1db7a6bd07fef196b0..8c280a68e2ddbbe24eb0d209311b221cddeb4a89 100644 (file)
@@ -32,7 +32,6 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 import com.typesafe.config.ConfigFactory;
-import io.netty.util.Timer;
 import java.io.File;
 import java.util.Iterator;
 import java.util.List;
@@ -100,6 +99,7 @@ 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.common.NetconfTimer;
 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;
@@ -190,7 +190,7 @@ public class MountPointEndToEndTest extends AbstractBaseSchemasTest {
     @Mock
     private AAAEncryptionService mockEncryptionService;
     @Mock
-    private Timer mockTimer;
+    private NetconfTimer mockTimer;
     @Mock
     private DeviceActionFactory deviceActionFactory;
     @Mock
index 9bd03ae2a94c040e7d9336f4a90424bbeded03d3..64a36ce299df314fea66ed09fcd1cd23ded1669b 100644 (file)
@@ -25,7 +25,6 @@ import static org.opendaylight.mdsal.binding.api.DataObjectModification.Modifica
 
 import akka.actor.ActorSystem;
 import akka.util.Timeout;
-import io.netty.util.Timer;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -58,6 +57,7 @@ import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
 import org.opendaylight.netconf.client.NetconfClientFactory;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.impl.DefaultSchemaResourceManager;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologySetup;
 import org.opendaylight.netconf.topology.singleton.impl.utils.NetconfTopologyUtils;
 import org.opendaylight.netconf.topology.spi.NetconfClientConfigurationBuilderFactory;
@@ -94,7 +94,7 @@ public class NetconfTopologyManagerTest extends AbstractBaseSchemasTest {
     @Mock
     private Registration mockRpcReg;
     @Mock
-    private Timer timer;
+    private NetconfTimer timer;
     @Mock
     private ExecutorService processingService;
     @Mock
index 93f818cd78f5f0b84b598d3b65a04cb2cdb1d592..df5605d01842b1f6774faec6253d456dacd53d9a 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.netconf.topology.spi;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
-import io.netty.util.Timer;
 import java.util.HashMap;
 import java.util.NoSuchElementException;
 import java.util.concurrent.ExecutionException;
@@ -23,6 +22,7 @@ import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 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.common.NetconfTimer;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev231121.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
@@ -45,7 +45,7 @@ public abstract class AbstractNetconfTopology {
     private final SchemaResourceManager schemaManager;
     private final BaseNetconfSchemas baseSchemas;
     private final NetconfClientConfigurationBuilderFactory builderFactory;
-    private final Timer timer;
+    private final NetconfTimer timer;
 
     protected final NetconfTopologySchemaAssembler schemaAssembler;
     protected final DataBroker dataBroker;
@@ -53,7 +53,7 @@ public abstract class AbstractNetconfTopology {
     protected final String topologyId;
 
     protected AbstractNetconfTopology(final String topologyId, final NetconfClientFactory clientFactory,
-            final Timer timer, final NetconfTopologySchemaAssembler schemaAssembler,
+            final NetconfTimer timer, final NetconfTopologySchemaAssembler schemaAssembler,
             final SchemaResourceManager schemaManager, final DataBroker dataBroker,
             final DOMMountPointService mountPointService, final NetconfClientConfigurationBuilderFactory builderFactory,
             final DeviceActionFactory deviceActionFactory, final BaseNetconfSchemas baseSchemas) {
index a025c83cfba6d7cc873eaa6004709d838f0c4898..9084c4a158ddd41058281059b13ae3fda9c32363 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import io.netty.util.Timeout;
-import io.netty.util.Timer;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CancellationException;
@@ -43,6 +42,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.spi.KeepaliveSalFacade;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev221225.NetconfNodeAugmentedOptional;
@@ -111,7 +111,7 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
     private final @NonNull NetconfClientConfiguration clientConfig;
     private final @NonNull NetconfDeviceCommunicator communicator;
     private final @NonNull RemoteDeviceHandler delegate;
-    private final @NonNull Timer timer;
+    private final @NonNull NetconfTimer timer;
     private final @NonNull RemoteDeviceId deviceId;
 
     private final long maxBackoff;
@@ -127,7 +127,7 @@ public final class NetconfNodeHandler extends AbstractRegistration implements Re
     @GuardedBy("this")
     private Task currentTask;
 
-    public NetconfNodeHandler(final NetconfClientFactory clientFactory, final Timer timer,
+    public NetconfNodeHandler(final NetconfClientFactory clientFactory, final NetconfTimer timer,
             final BaseNetconfSchemas baseSchemas, final SchemaResourceManager schemaManager,
             final NetconfTopologySchemaAssembler schemaAssembler,
             final NetconfClientConfigurationBuilderFactory builderFactory,
index 165fb5ccf5ad161cd876915c686fc194d2148eb9..8c05becd2d64a1f70830a425af6dbcc1231a00cf 100644 (file)
@@ -24,7 +24,6 @@ import com.google.common.net.InetAddresses;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.SettableFuture;
 import io.netty.util.Timeout;
-import io.netty.util.Timer;
 import io.netty.util.TimerTask;
 import java.net.InetSocketAddress;
 import java.util.List;
@@ -55,6 +54,7 @@ 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.DefaultBaseNetconfSchemas;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
@@ -80,7 +80,7 @@ public class NetconfNodeHandlerTest {
 
     // Core setup
     @Mock
-    private Timer timer;
+    private NetconfTimer timer;
     @Mock
     private SchemaResourceManager schemaManager;
     @Mock
index dc5c7364778949ba3515f4c7219372368cdaa7a8..74175125b092976fd76990a6c11343cab9661a92 100644 (file)
                 <artifactId>netconf-client</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-common-mdsal</artifactId>
index 9420362a4e5bbcf694dc7508512e1b4978d76d77..579f3d85e46cf5a070906d3e80385a95470d5752 100644 (file)
     <packaging>feature</packaging>
 
     <dependencies>
-        <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>odl-controller-exp-netty-config</artifactId>
-            <type>xml</type>
-            <classifier>features</classifier>
-        </dependency>
         <dependency>
             <groupId>org.opendaylight.netconf</groupId>
             <artifactId>odl-netconf-netty-util</artifactId>
diff --git a/features/odl-netconf-client/src/main/feature/feature.xml b/features/odl-netconf-client/src/main/feature/feature.xml
deleted file mode 100644 (file)
index 8a95fcc..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright Â© 2020 PANTHEON.tech, s.r.o. and others.
-  ~
-  ~ 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
-  -->
-<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-netconf-client-${project.version}">
-    <feature name="odl-netconf-client" version="${project.version}">
-        <feature version="[8,9)">odl-controller-exp-netty-config</feature>
-    </feature>
-</features>
index af9dd7fe7d4b9d709791c47786e029c91b5d0aab..54d9a05768f96baef08ed2b51213f3bff632329f 100644 (file)
@@ -7,8 +7,9 @@
  */
 package org.opendaylight.netconf.callhome.server;
 
+import static java.util.Objects.requireNonNull;
+
 import io.netty.handler.ssl.SslHandler;
-import io.netty.util.concurrent.Promise;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.netconf.client.ClientChannelInitializer;
 import org.opendaylight.netconf.client.NetconfClientSession;
@@ -21,19 +22,19 @@ import org.slf4j.LoggerFactory;
 public class CallHomeTransportChannelListener implements TransportChannelListener {
     private static final Logger LOG = LoggerFactory.getLogger(CallHomeTransportChannelListener.class);
 
-    final NetconfClientSessionNegotiatorFactory negotiationFactory;
-    final CallHomeSessionContextManager<?> contextManager;
-    final CallHomeStatusRecorder statusRecorder;
+    private final @NonNull NetconfClientSessionNegotiatorFactory negotiationFactory;
+    private final CallHomeSessionContextManager<?> contextManager;
+    private final CallHomeStatusRecorder statusRecorder;
 
     public CallHomeTransportChannelListener(final NetconfClientSessionNegotiatorFactory negotiationFactory,
             final CallHomeSessionContextManager<?> contextManager, final CallHomeStatusRecorder statusRecorder) {
-        this.negotiationFactory = negotiationFactory;
-        this.contextManager = contextManager;
-        this.statusRecorder = statusRecorder;
+        this.negotiationFactory = requireNonNull(negotiationFactory);
+        this.contextManager = requireNonNull(contextManager);
+        this.statusRecorder = requireNonNull(statusRecorder);
     }
 
     @Override
-    public void onTransportChannelEstablished(@NonNull TransportChannel transportChannel) {
+    public void onTransportChannelEstablished(final TransportChannel transportChannel) {
         final var channel = transportChannel.channel();
 
         // identify or create session context associated with current connection
@@ -48,7 +49,7 @@ public class CallHomeTransportChannelListener implements TransportChannelListene
         LOG.info("Starting netconf negotiation for context: {}", context);
 
         // init NETCONF negotiation
-        final Promise<NetconfClientSession> promise = channel.eventLoop().newPromise();
+        final var promise = channel.eventLoop().<NetconfClientSession>newPromise();
         promise.addListener(ignored -> {
             final var cause = promise.cause();
             if (cause != null) {
@@ -72,7 +73,7 @@ public class CallHomeTransportChannelListener implements TransportChannelListene
     }
 
     @Override
-    public void onTransportChannelFailed(@NonNull Throwable cause) {
+    public void onTransportChannelFailed(final Throwable cause) {
         statusRecorder.onTransportChannelFailure(cause);
     }
 }
index 5bb353137f72e8dcf146d02f685a3cf121587557..5708f5d448c18ecc21e036722593426dff435f18 100644 (file)
@@ -8,15 +8,12 @@
 package org.opendaylight.netconf.callhome.server.ssh;
 
 import static java.util.Objects.requireNonNull;
-import static org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES;
 
 import com.google.common.annotations.VisibleForTesting;
-import io.netty.util.HashedWheelTimer;
 import java.net.InetAddress;
 import java.net.SocketAddress;
 import java.security.PublicKey;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -164,43 +161,43 @@ public final class CallHomeSshServer implements AutoCloseable {
             return new CallHomeSshServer(
                 toServerParams(address, port),
                 transportStackFactory == null ? defaultTransportStackFactory() : transportStackFactory,
-                negotiationFactory == null ? defaultNegotiationFactory() : negotiationFactory,
+                negotiationFactory,
                 contextManager == null ? new CallHomeSshSessionContextManager() : contextManager,
                 authProvider, statusRecorder);
         }
 
         public Builder withAuthProvider(final CallHomeSshAuthProvider newAuthProvider) {
-            this.authProvider = newAuthProvider;
+            authProvider = newAuthProvider;
             return this;
         }
 
         public Builder withSessionContextManager(final CallHomeSshSessionContextManager newContextManager) {
-            this.contextManager = newContextManager;
+            contextManager = newContextManager;
             return this;
         }
 
         public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) {
-            this.statusRecorder = newStatusRecorder;
+            statusRecorder = newStatusRecorder;
             return this;
         }
 
         public Builder withAddress(final InetAddress newAddress) {
-            this.address = newAddress;
+            address = newAddress;
             return this;
         }
 
         public Builder withPort(final int newPort) {
-            this.port = newPort;
+            port = newPort;
             return this;
         }
 
         public Builder withTransportStackFactory(final SSHTransportStackFactory newTransportStackFactory) {
-            this.transportStackFactory = newTransportStackFactory;
+            transportStackFactory = newTransportStackFactory;
             return this;
         }
 
         public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) {
-            this.negotiationFactory = newNegotiationFactory;
+            negotiationFactory = newNegotiationFactory;
             return this;
         }
     }
@@ -215,9 +212,4 @@ public final class CallHomeSshServer implements AutoCloseable {
     private static SSHTransportStackFactory defaultTransportStackFactory() {
         return new SSHTransportStackFactory("ssh-call-home-server", 0);
     }
-
-    private static NetconfClientSessionNegotiatorFactory defaultNegotiationFactory() {
-        return new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer(),
-            Optional.empty(), DEFAULT_TIMEOUT_MILLIS, DEFAULT_CLIENT_CAPABILITIES);
-    }
 }
index faa210d7d5a1b9c77a0c56b925cad94d834921fd..4fccee7566f3abb10888fdc8aed5c9fccc515005 100644 (file)
@@ -8,12 +8,9 @@
 package org.opendaylight.netconf.callhome.server.tls;
 
 import static java.util.Objects.requireNonNull;
-import static org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES;
 
 import io.netty.channel.ChannelOption;
-import io.netty.util.HashedWheelTimer;
 import java.net.InetAddress;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -92,52 +89,51 @@ public final class CallHomeTlsServer implements AutoCloseable {
                 bootstrapFactory == null ? defaultBootstrapFactory() : bootstrapFactory,
                 maxConnections == null ? DEFAULT_MAX_CONNECTIONS : maxConnections,
                 timeoutMillis == null ? DEFAULT_TIMEOUT_MILLIS : timeoutMillis,
-                negotiationFactory == null ? defaultNegotiationFactory() : negotiationFactory,
-                contextManager, authProvider, statusRecorder);
+                negotiationFactory, contextManager, authProvider, statusRecorder);
         }
 
         public Builder withSessionContextManager(final CallHomeTlsSessionContextManager newContextManager) {
-            this.contextManager = newContextManager;
+            contextManager = newContextManager;
             return this;
         }
 
         public Builder withAuthProvider(final CallHomeTlsAuthProvider newAuthProvider) {
-            this.authProvider = newAuthProvider;
+            authProvider = newAuthProvider;
             return this;
         }
 
         public Builder withStatusRecorder(final CallHomeStatusRecorder newStatusRecorder) {
-            this.statusRecorder = newStatusRecorder;
+            statusRecorder = newStatusRecorder;
             return this;
         }
 
         public Builder withAddress(final InetAddress newAddress) {
-            this.address = newAddress;
+            address = newAddress;
             return this;
         }
 
         public Builder withPort(final int newPort) {
-            this.port = newPort;
+            port = newPort;
             return this;
         }
 
         public Builder withMaxConnections(final int newMaxConnections) {
-            this.maxConnections = newMaxConnections;
+            maxConnections = newMaxConnections;
             return this;
         }
 
         public Builder withTimeout(final int newTimeoutMillis) {
-            this.timeoutMillis = newTimeoutMillis;
+            timeoutMillis = newTimeoutMillis;
             return this;
         }
 
         public Builder withBootstrapFactory(final BootstrapFactory newBootstrapFactory) {
-            this.bootstrapFactory = newBootstrapFactory;
+            bootstrapFactory = newBootstrapFactory;
             return this;
         }
 
         public Builder withNegotiationFactory(final NetconfClientSessionNegotiatorFactory newNegotiationFactory) {
-            this.negotiationFactory = newNegotiationFactory;
+            negotiationFactory = newNegotiationFactory;
             return this;
         }
     }
@@ -152,9 +148,4 @@ public final class CallHomeTlsServer implements AutoCloseable {
     private static BootstrapFactory defaultBootstrapFactory() {
         return new BootstrapFactory("tls-call-home-server", 0);
     }
-
-    private static NetconfClientSessionNegotiatorFactory defaultNegotiationFactory() {
-        return new NetconfClientSessionNegotiatorFactory(new HashedWheelTimer(),
-            Optional.empty(), DEFAULT_TIMEOUT_MILLIS, DEFAULT_CLIENT_CAPABILITIES);
-    }
 }
\ No newline at end of file
index 63fdafbb3a3199b02063a08e3130ee12e1b4aa61..95527aabe6113c2b04a5d289faa22bf9e87a846a 100644 (file)
@@ -17,17 +17,15 @@ import static org.mockito.Mockito.verify;
 import static org.opendaylight.netconf.api.TransportConstants.SSH_SUBSYSTEM;
 
 import com.google.common.util.concurrent.SettableFuture;
-import io.netty.util.HashedWheelTimer;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
-import java.net.SocketAddress;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
-import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import org.eclipse.jdt.annotation.Nullable;
@@ -39,6 +37,8 @@ import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
 import org.opendaylight.netconf.callhome.server.ssh.CallHomeSshAuthSettings.DefaultAuthSettings;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.server.NetconfServerSession;
 import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.netconf.server.ServerTransportInitializer;
@@ -89,24 +89,21 @@ public class CallHomeSshServerTest {
         final var client4Keys = generateKeyPair();
 
         // Auth provider
-        final var authProvider = new CallHomeSshAuthProvider() {
-            @Override
-            public CallHomeSshAuthSettings provideAuth(final SocketAddress remoteAddress, final PublicKey publicKey) {
-                // identify client 2 by password (invalid)
-                if (client2Keys.getPublic().equals(publicKey)) {
-                    return new DefaultAuthSettings("client2-id", USERNAME, Set.of("invalid-password"), null);
-                }
-                // identify client 3 by password (valid)
-                if (client3Keys.getPublic().equals(publicKey)) {
-                    return new DefaultAuthSettings("client3-id", USERNAME, Set.of(PASSWORD), null);
-                }
-                // identify client 4 by public key
-                if (client4Keys.getPublic().equals(publicKey)) {
-                    return new DefaultAuthSettings("client4-id", USERNAME, null, Set.of(serverKeys));
-                }
-                // client 1 is not identified
-                return null;
+        final var authProvider = (CallHomeSshAuthProvider) (remoteAddress, publicKey) -> {
+            // identify client 2 by password (invalid)
+            if (client2Keys.getPublic().equals(publicKey)) {
+                return new DefaultAuthSettings("client2-id", USERNAME, Set.of("invalid-password"), null);
+            }
+            // identify client 3 by password (valid)
+            if (client3Keys.getPublic().equals(publicKey)) {
+                return new DefaultAuthSettings("client3-id", USERNAME, Set.of(PASSWORD), null);
             }
+            // identify client 4 by public key
+            if (client4Keys.getPublic().equals(publicKey)) {
+                return new DefaultAuthSettings("client4-id", USERNAME, null, Set.of(serverKeys));
+            }
+            // client 1 is not identified
+            return null;
         };
         // client side authenticators
         final PasswordAuthenticator passwordAuthenticator =
@@ -118,8 +115,10 @@ public class CallHomeSshServerTest {
         doReturn(serverSessionListener).when(monitoringService).getSessionListener();
         doReturn(EMPTY_CAPABILITIES).when(monitoringService).getCapabilities();
 
+        final var timer = new DefaultNetconfTimer();
+
         final var negotiatorFactory = NetconfServerSessionNegotiatorFactory.builder()
-            .setTimer(new HashedWheelTimer())
+            .setTimer(timer)
             .setAggregatedOpService(new AggregatedNetconfOperationServiceFactory())
             .setIdProvider(new DefaultSessionIdProvider())
             .setConnectionTimeoutMillis(TIMEOUT)
@@ -138,7 +137,7 @@ public class CallHomeSshServerTest {
         final var contextManager = new CallHomeSshSessionContextManager() {
             // inject netconf session listener
             @Override
-            public CallHomeSshSessionContext createContext(String id, ClientSession clientSession) {
+            public CallHomeSshSessionContext createContext(final String id, final ClientSession clientSession) {
                 return new CallHomeSshSessionContext(id, clientSession.getRemoteAddress(), clientSession,
                     clientSessionListener, SettableFuture.create());
             }
@@ -150,6 +149,8 @@ public class CallHomeSshServerTest {
             .withAuthProvider(authProvider)
             .withSessionContextManager(contextManager)
             .withStatusRecorder(statusRecorder)
+            .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT,
+                NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
             .build();
 
         SSHServer client1 = null;
@@ -211,6 +212,7 @@ public class CallHomeSshServerTest {
             shutdownClient(client2);
             shutdownClient(client3);
             shutdownClient(client4);
+            timer.close();
         }
 
         // verify disconnect reported
index 03e2afe41da1ed8a633e5a9bec3157f4e5839745..4bce3578d068332a2636ea07ee8437b26e6763c2 100644 (file)
@@ -20,7 +20,6 @@ import io.netty.channel.Channel;
 import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.SslContextBuilder;
 import io.netty.handler.ssl.SslHandler;
-import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Promise;
 import java.math.BigInteger;
 import java.net.InetAddress;
@@ -36,6 +35,7 @@ import java.security.spec.RSAKeyGenParameterSpec;
 import java.time.Duration;
 import java.time.Instant;
 import java.util.Date;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -56,6 +56,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.netconf.callhome.server.CallHomeStatusRecorder;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
+import org.opendaylight.netconf.client.NetconfClientSessionNegotiatorFactory;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer;
 import org.opendaylight.netconf.server.NetconfServerSession;
 import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory;
@@ -120,7 +122,8 @@ public class CallHomeTlsServerTest {
         // Auth provider
         final var authProvider = new CallHomeTlsAuthProvider() {
             @Override
-            public @Nullable String idFor(@NonNull PublicKey publicKey) {
+            public @Nullable String idFor(@NonNull
+            final PublicKey publicKey) {
                 // identify client 3 only
                 return clientCert3.keyPair.getPublic().equals(publicKey) ? "client-id" : null;
             }
@@ -135,8 +138,10 @@ public class CallHomeTlsServerTest {
         doReturn(serverSessionListener).when(monitoringService).getSessionListener();
         doReturn(EMPTY_CAPABILITIES).when(monitoringService).getCapabilities();
 
+        final var timer = new DefaultNetconfTimer();
+
         final var negotiatorFactory = NetconfServerSessionNegotiatorFactory.builder()
-            .setTimer(new HashedWheelTimer())
+            .setTimer(timer)
             .setAggregatedOpService(new AggregatedNetconfOperationServiceFactory())
             .setIdProvider(new DefaultSessionIdProvider())
             .setConnectionTimeoutMillis(TIMEOUT)
@@ -165,6 +170,8 @@ public class CallHomeTlsServerTest {
             .withAuthProvider(authProvider)
             .withSessionContextManager(contextMgr)
             .withStatusRecorder(statusRecorder)
+            .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT,
+                NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
             .withPort(serverPort).build();
 
         TLSServer client1 = null;
@@ -200,6 +207,7 @@ public class CallHomeTlsServerTest {
             shutdownClient(client1);
             shutdownClient(client2);
             shutdownClient(client3);
+            timer.close();
         }
 
         // validate disconnect reported
index 928dd188577da98313445d9098852f3f44e200e2..c728068cfca1b2a2dce695f2c82f9c138662d7e3 100644 (file)
       <groupId>org.opendaylight.netconf</groupId>
       <artifactId>netconf-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>netconf-common</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.netconf</groupId>
       <artifactId>shaded-exificient</artifactId>
index 7e2e1fff31b451c79833b3d3115f0fac0d5a60cc..3e16d1fb21634709ecf63470073a190d5baacc1b 100644 (file)
@@ -18,7 +18,6 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.handler.ssl.SslHandler;
 import io.netty.util.Timeout;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
 import java.util.concurrent.TimeUnit;
@@ -34,6 +33,7 @@ import org.opendaylight.netconf.api.NetconfSessionListener;
 import org.opendaylight.netconf.api.messages.HelloMessage;
 import org.opendaylight.netconf.api.messages.NetconfMessage;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
 import org.opendaylight.netconf.nettyutil.handler.NetconfMessageToXMLEncoder;
@@ -92,7 +92,7 @@ public abstract class NetconfSessionNegotiator<S extends AbstractNetconfSession<
     private final long connectionTimeoutMillis;
     private final Promise<S> promise;
     private final L sessionListener;
-    private final Timer timer;
+    private final NetconfTimer timer;
 
     @GuardedBy("this")
     private Timeout timeoutTask;
@@ -100,12 +100,12 @@ public abstract class NetconfSessionNegotiator<S extends AbstractNetconfSession<
     private State state = State.IDLE;
 
     protected NetconfSessionNegotiator(final HelloMessage hello, final Promise<S> promise, final Channel channel,
-            final Timer timer, final L sessionListener, final long connectionTimeoutMillis,
+            final NetconfTimer timer, final L sessionListener, final long connectionTimeoutMillis,
             final @NonNegative int maximumIncomingChunkSize) {
         localHello = requireNonNull(hello);
         this.promise = requireNonNull(promise);
         this.channel = requireNonNull(channel);
-        this.timer = timer;
+        this.timer = requireNonNull(timer);
         this.sessionListener = sessionListener;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
         this.maximumIncomingChunkSize = maximumIncomingChunkSize;
index 4e6952f90926215cb483291cb740e34d7e0e3323..323c6aa056311ad51d62d7663758c381f72e785f 100644 (file)
@@ -32,7 +32,6 @@ import io.netty.channel.ChannelPromise;
 import io.netty.channel.embedded.EmbeddedChannel;
 import io.netty.handler.ssl.SslHandler;
 import io.netty.util.Timeout;
-import io.netty.util.Timer;
 import io.netty.util.TimerTask;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.Promise;
@@ -51,6 +50,7 @@ import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.api.NetconfSessionListener;
 import org.opendaylight.netconf.api.messages.HelloMessage;
 import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
@@ -66,7 +66,7 @@ public class AbstractNetconfSessionNegotiatorTest {
     @Mock
     private SslHandler sslHandler;
     @Mock
-    private Timer timer;
+    private NetconfTimer timer;
     @Mock
     private Timeout timeout;
     private EmbeddedChannel channel;
index c6353662f9765c9c4706be9f99e034cde9b79da1..20690f7fad804f03d0d368f8d9facbf35d68d55b 100644 (file)
@@ -14,7 +14,6 @@ import static org.opendaylight.netconf.nettyutil.AbstractChannelInitializer.NETC
 
 import io.netty.channel.ChannelInboundHandlerAdapter;
 import io.netty.channel.embedded.EmbeddedChannel;
-import io.netty.util.HashedWheelTimer;
 import io.netty.util.concurrent.Promise;
 import java.util.Optional;
 import java.util.Set;
@@ -26,6 +25,7 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.api.NetconfSessionListener;
 import org.opendaylight.netconf.api.messages.HelloMessage;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.EOMFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.NetconfChunkAggregator;
@@ -55,7 +55,8 @@ public class Netconf539Test {
         channel.pipeline().addLast(NETCONF_MESSAGE_AGGREGATOR, new NetconfEOMAggregator());
         final HelloMessage serverHello = HelloMessage.createClientHello(Set.of(CapabilityURN.BASE_1_1),
             Optional.empty());
-        negotiator = new TestSessionNegotiator(serverHello, promise, channel, new HashedWheelTimer(), listener, 100L);
+        negotiator = new TestSessionNegotiator(serverHello, promise, channel, new DefaultNetconfTimer(), listener,
+            100L);
     }
 
     @Test
index d7bcb1525ebf589ccecbf395d76fb25e6a6991c5..4af6b430afdd3c1a31cb84fad4a7c0d5c345f278 100644 (file)
@@ -8,17 +8,17 @@
 package org.opendaylight.netconf.nettyutil;
 
 import io.netty.channel.Channel;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import org.opendaylight.netconf.api.NetconfSessionListener;
 import org.opendaylight.netconf.api.messages.HelloMessage;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
 import org.opendaylight.yangtools.yang.common.Uint32;
 
 final class TestSessionNegotiator
         extends NetconfSessionNegotiator<TestingNetconfSession, NetconfSessionListener<TestingNetconfSession>> {
     TestSessionNegotiator(final HelloMessage hello, final Promise<TestingNetconfSession> promise,
-            final Channel channel, final Timer timer,
+            final Channel channel, final NetconfTimer timer,
             final NetconfSessionListener<TestingNetconfSession> sessionListener, final long connectionTimeoutMillis) {
         super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, 16384);
     }
index 33c4d9c0fc6b6ffad41f15bec7964c491e1227ee..1e2a2002939158c99dac83b75952d779de1d8af5 100644 (file)
@@ -12,7 +12,6 @@ import static java.util.Objects.requireNonNullElseGet;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.ImmutableList;
 import com.google.common.util.concurrent.Futures;
-import io.netty.util.HashedWheelTimer;
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetAddress;
@@ -27,6 +26,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.stream.IntStream;
 import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.api.TransportConstants;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.server.ServerTransportInitializer;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
 import org.opendaylight.netconf.server.api.monitoring.BasicCapability;
@@ -77,7 +77,7 @@ import org.slf4j.LoggerFactory;
 public class NetconfDeviceSimulator implements Closeable {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceSimulator.class);
 
-    private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer();
+    private final DefaultNetconfTimer timer = new DefaultNetconfTimer();
     private final Configuration configuration;
     private final List<TransportStack> servers;
     private final SSHTransportStackFactory sshStackFactory;
@@ -109,8 +109,8 @@ public class NetconfDeviceSimulator implements Closeable {
         final var aggregatedNetconfOperationServiceFactory = createOperationServiceFactory(
             sourceProvider, transformedCapabilities, monitoringService1, idProvider);
 
-        return new ServerTransportInitializer(new TesttoolNegotiationFactory(
-            hashedWheelTimer, aggregatedNetconfOperationServiceFactory, idProvider,
+        return new ServerTransportInitializer(new TesttoolNegotiationFactory(timer,
+            aggregatedNetconfOperationServiceFactory, idProvider,
             configuration.getGenerateConfigsTimeout(), monitoringService1, configuration.getCapabilities()));
     }
 
index e26db5e404ab26e665e305e5d71e39c96fa52ee1..4ce4df4ce2f81224a00f3aef537fc9a2773a2f1b 100644 (file)
@@ -7,11 +7,11 @@
  */
 package org.opendaylight.netconf.test.tool;
 
-import io.netty.util.Timer;
 import java.net.SocketAddress;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
 import org.opendaylight.netconf.server.api.monitoring.NetconfMonitoringService;
@@ -26,16 +26,17 @@ public class TesttoolNegotiationFactory extends NetconfServerSessionNegotiatorFa
 
     private final ConcurrentMap<SocketAddress, NetconfOperationService> operationServices = new ConcurrentHashMap<>();
 
-    public TesttoolNegotiationFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
-            final SessionIdProvider idProvider, final long connectionTimeoutMillis,
-            final NetconfMonitoringService monitoringService) {
+    public TesttoolNegotiationFactory(final NetconfTimer timer,
+            final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider,
+            final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService) {
         super(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis, monitoringService,
             NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES);
     }
 
-    public TesttoolNegotiationFactory(final Timer timer, final NetconfOperationServiceFactory netconfOperationProvider,
-            final SessionIdProvider idProvider, final long connectionTimeoutMillis,
-            final NetconfMonitoringService monitoringService, final Set<String> baseCapabilities) {
+    public TesttoolNegotiationFactory(final NetconfTimer timer,
+            final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider,
+            final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService,
+            final Set<String> baseCapabilities) {
         super(timer, netconfOperationProvider, idProvider, connectionTimeoutMillis,
             monitoringService, baseCapabilities);
     }
index 9b1c30d244f83840a7773b37f6a34f2ee1c0f1be..ed2b31a742babf2b547565001b5c4fc30e66a620 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceCommunicator;
 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.test.tool.TestToolUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.CommitInput;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.EditConfigInput;
@@ -165,29 +166,30 @@ public final class StressClient {
             }
         }
 
-        final var netconfClientFactory = new NetconfClientFactoryImpl();
+        try (var timer = new DefaultNetconfTimer()) {
+            try (var netconfClientFactory = new NetconfClientFactoryImpl(timer)) {
 
-        final var callables = new ArrayList<StressClientCallable>(threadAmount);
-        for (var messages : allPreparedMessages) {
-            callables.add(new StressClientCallable(params, netconfClientFactory, getBaseConfiguration(), messages));
-        }
-
-        final var executorService = Executors.newFixedThreadPool(threadAmount);
+                final var callables = new ArrayList<StressClientCallable>(threadAmount);
+                for (var messages : allPreparedMessages) {
+                    callables.add(new StressClientCallable(params, netconfClientFactory, getBaseConfiguration(),
+                        messages));
+                }
 
-        LOG.info("Starting stress test");
-        final var sw = Stopwatch.createStarted();
-        final var futures = executorService.invokeAll(callables);
-        for (var future : futures) {
-            future.get(4L, TimeUnit.MINUTES);
-        }
-        executorService.shutdownNow();
-        sw.stop();
+                final var executorService = Executors.newFixedThreadPool(threadAmount);
 
-        LOG.info("FINISHED. Execution time: {}", sw);
-        LOG.info("Requests per second: {}", params.editCount * 1000.0 / sw.elapsed(TimeUnit.MILLISECONDS));
+                LOG.info("Starting stress test");
+                final var sw = Stopwatch.createStarted();
+                final var futures = executorService.invokeAll(callables);
+                for (var future : futures) {
+                    future.get(4L, TimeUnit.MINUTES);
+                }
+                executorService.shutdownNow();
+                sw.stop();
 
-        // Cleanup
-        netconfClientFactory.close();
+                LOG.info("FINISHED. Execution time: {}", sw);
+                LOG.info("Requests per second: {}", params.editCount * 1000.0 / sw.elapsed(TimeUnit.MILLISECONDS));
+            }
+        }
     }
 
     static NetconfMessage prepareMessage(final int id, final String editContentString) {
index f16bf76611d9faeb8fa49419457f73c7d2123024..3b25a0127334021274dc1131e5ef9c6c85382cba 100644 (file)
@@ -36,6 +36,7 @@ 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.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.test.tool.config.Configuration;
 import org.opendaylight.netconf.test.tool.config.ConfigurationBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.crypto.types.rev231228.password.grouping.password.type.CleartextPasswordBuilder;
@@ -101,6 +102,7 @@ public class TestToolTest {
         "ncmon", "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
     );
 
+    private static DefaultNetconfTimer timer;
     private static NetconfClientFactory clientFactory;
     private static NetconfDeviceSimulator tcpDeviceSimulator;
     private static NetconfDeviceSimulator sshDeviceSimulator;
@@ -109,7 +111,8 @@ public class TestToolTest {
 
     @BeforeAll
     static void beforeAll() {
-        clientFactory = new NetconfClientFactoryImpl();
+        timer = new DefaultNetconfTimer();
+        clientFactory = new NetconfClientFactoryImpl(timer);
         tcpDeviceSimulator = new NetconfDeviceSimulator(getSimulatorConfig(TCP));
         tcpDevicePort = startSimulator(tcpDeviceSimulator);
         sshDeviceSimulator = new NetconfDeviceSimulator(getSimulatorConfig(SSH));
@@ -123,6 +126,7 @@ public class TestToolTest {
         stopSimulator(sshDeviceSimulator);
         sshDeviceSimulator = null;
         clientFactory.close();
+        timer.close();
     }
 
     @ParameterizedTest(name = "Custom RPC -- RFC7950 {0}")
index 833c80c9f5f1dcb4f7b34d6f01906c6adb082455..d9551a7b026bed17628ada2fe858f838bc54f942 100644 (file)
@@ -19,7 +19,6 @@ import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 import io.netty.util.Timeout;
-import io.netty.util.Timer;
 import io.netty.util.TimerTask;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.TimeUnit;
@@ -37,6 +36,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
 import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.GetConfig;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -60,7 +60,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
 
     private final RemoteDeviceHandler deviceHandler;
     private final RemoteDeviceId deviceId;
-    private final Timer timer;
+    private final NetconfTimer timer;
     private final long keepaliveDelaySeconds;
     private final long timeoutNanos;
     private final long delayNanos;
@@ -68,8 +68,8 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
     private volatile NetconfDeviceCommunicator listener;
     private volatile KeepaliveTask task;
 
-    public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler, final Timer timer,
-            final long keepaliveDelaySeconds, final long requestTimeoutMillis) {
+    public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler,
+            final NetconfTimer timer, final long keepaliveDelaySeconds, final long requestTimeoutMillis) {
         this.deviceId = requireNonNull(deviceId);
         this.deviceHandler = requireNonNull(deviceHandler);
         this.timer = requireNonNull(timer);
@@ -79,7 +79,7 @@ public final class KeepaliveSalFacade implements RemoteDeviceHandler {
     }
 
     public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler,
-            final Timer timer) {
+            final NetconfTimer timer) {
         this(deviceId, deviceHandler, timer, DEFAULT_DELAY, DEFAULT_TRANSACTION_TIMEOUT_MILLI);
     }
 
index f1f1a5fa2f05af741a8230ac53c04b80349d86e4..b6fe7827700481fa4c4f56c6d2a1537ac55b8926 100644 (file)
@@ -13,8 +13,6 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
 import com.google.common.util.concurrent.SettableFuture;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
 import java.net.InetSocketAddress;
 import org.eclipse.jdt.annotation.NonNull;
 import org.junit.jupiter.api.AfterEach;
@@ -35,6 +33,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
 import org.opendaylight.netconf.client.mdsal.impl.NetconfBaseOps;
 import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.GetConfig;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
@@ -52,14 +51,14 @@ class KeepaliveSalFacadeResponseWaitingTest {
     private Rpcs.Normalized deviceRpc;
     @Mock
     private NetconfDeviceCommunicator listener;
-    private Timer timer;
+    private DefaultNetconfTimer timer;
 
     private KeepaliveSalFacade keepaliveSalFacade;
     private LocalNetconfSalFacade underlyingSalFacade;
 
     @BeforeEach
     void beforeEach() {
-        timer = new HashedWheelTimer();
+        timer = new DefaultNetconfTimer();
 
         underlyingSalFacade = new LocalNetconfSalFacade();
         keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 2L, 10000L);
@@ -68,7 +67,7 @@ class KeepaliveSalFacadeResponseWaitingTest {
 
     @AfterEach
     void afterEach() {
-        timer.stop();
+        timer.close();
     }
 
     /**
index cd17b638291e89a1e1b7feab906f8ae5e25e2f0c..cc438d0ce1db18e9587120b727b9f88c7e2b93d5 100644 (file)
@@ -21,8 +21,6 @@ import static org.mockito.Mockito.verify;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.SettableFuture;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
 import java.net.InetSocketAddress;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -37,6 +35,7 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
 import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -54,20 +53,20 @@ class KeepaliveSalFacadeTest {
     @Mock
     private Rpcs.Normalized deviceRpc;
 
-    private Timer timer;
+    private DefaultNetconfTimer timer;
     private KeepaliveSalFacade keepaliveSalFacade;
     private Rpcs proxyRpc;
 
     @BeforeEach
     void beforeEach() {
-        timer = new HashedWheelTimer();
+        timer = new DefaultNetconfTimer();
         keepaliveSalFacade = new KeepaliveSalFacade(REMOTE_DEVICE_ID, underlyingSalFacade, timer, 1L, 1L);
         keepaliveSalFacade.setListener(listener);
     }
 
     @AfterEach
     void afterEach() {
-        timer.stop();
+        timer.close();
     }
 
     @Test
index 6484baa0e15c5d22850544f4784cbf4fb9a68fda..5cd445aba1cbafac72a191d478bc62179ad571c1 100644 (file)
       <groupId>io.netty</groupId>
       <artifactId>netty-transport</artifactId>
     </dependency>
+    <dependency>
+      <groupId>jakarta.annotation</groupId>
+      <artifactId>jakarta.annotation-api</artifactId>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
     <dependency>
       <groupId>org.checkerframework</groupId>
       <artifactId>checker-qual</artifactId>
index b9c5de2667d00548a8c0b8db82fc569d06364e82..9f86a1a660899fdeb5a8feb37c45695a5e0ceb3c 100644 (file)
@@ -15,11 +15,11 @@ import static org.opendaylight.netconf.client.conf.NetconfClientConfiguration.Ne
 import com.google.common.collect.ImmutableSet;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
+import javax.annotation.PreDestroy;
 import javax.inject.Singleton;
 import org.opendaylight.netconf.api.TransportConstants;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.transport.api.TransportChannel;
 import org.opendaylight.netconf.transport.api.TransportChannelListener;
 import org.opendaylight.netconf.transport.api.UnsupportedConfigurationException;
@@ -30,27 +30,30 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
 
 @Singleton
+// FIXME: drop the property and use lazy activation
 @Component(immediate = true, service = NetconfClientFactory.class, property = "type=netconf-client-factory")
 public class NetconfClientFactoryImpl implements NetconfClientFactory {
-    private final Timer timer = new HashedWheelTimer();
     private final SSHTransportStackFactory factory;
+    private final NetconfTimer timer;
 
-    @Activate
-    public NetconfClientFactoryImpl() {
-        // TODO make factory component configurable for osgi
-        this(new SSHTransportStackFactory("odl-netconf-client", 0));
+    public NetconfClientFactoryImpl(final NetconfTimer timer, final SSHTransportStackFactory factory) {
+        this.timer = requireNonNull(timer);
+        this.factory = requireNonNull(factory);
     }
 
-    public NetconfClientFactoryImpl(final SSHTransportStackFactory factory) {
-        this.factory = requireNonNull(factory);
+    @Activate
+    public NetconfClientFactoryImpl(@Reference final NetconfTimer timer) {
+        // FIXME: make factory component configurable for OSGi
+        this(timer, new SSHTransportStackFactory("odl-netconf-client", 0));
     }
 
+    @PreDestroy
     @Deactivate
     @Override
     public void close() {
-        timer.stop();
         factory.close();
     }
 
index beb9282ba97a5aab0e208548cf14c6d3c870d1e7..8455821ef5aca833b14fff2dfef0e6ac52589f4d 100644 (file)
@@ -15,7 +15,6 @@ import com.google.common.collect.Interners;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import java.util.Set;
 import javax.xml.xpath.XPathConstants;
@@ -29,6 +28,7 @@ import org.opendaylight.netconf.api.messages.NetconfMessage;
 import org.opendaylight.netconf.api.messages.RpcMessage;
 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer;
 import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
@@ -57,7 +57,7 @@ class NetconfClientSessionNegotiator
     private final RpcMessage startExi;
 
     NetconfClientSessionNegotiator(final HelloMessage hello, final RpcMessage startExi,
-            final Promise<NetconfClientSession> promise, final Channel channel, final Timer timer,
+            final Promise<NetconfClientSession> promise, final Channel channel, final NetconfTimer timer,
             final NetconfClientSessionListener sessionListener, final long connectionTimeoutMillis,
             final @NonNegative int maximumIncomingChunkSize) {
         super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, maximumIncomingChunkSize);
@@ -206,10 +206,9 @@ class NetconfClientSessionNegotiator
 
                 // Unexpected response to start-exi, throwing message away, continue without exi
             } else {
-                LOG.warn("Unexpected response to start-exi message, should be ok, was {}, "
-                        + "Communication will continue without exi "
-                        + "and response message will be thrown away on session {}",
-                        netconfMessage, session);
+                LOG.warn("""
+                    Unexpected response to start-exi message, should be ok, was {}. Communication will continue \
+                    without EXI and response message will be thrown away on session {}""", netconfMessage, session);
             }
 
             negotiationSuccessful(session);
index d49d3a2684e72fbfc09033c7a4eda7e49f9d1141..7b2f464b44f56ad89ad84e394752fe2d0abdd9c5 100644 (file)
@@ -11,7 +11,6 @@ import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableSet;
 import io.netty.channel.Channel;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import java.util.Optional;
 import java.util.Set;
@@ -20,6 +19,7 @@ import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.api.NetconfSessionListenerFactory;
 import org.opendaylight.netconf.api.messages.HelloMessage;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator;
 import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
 import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessageProvider;
@@ -66,16 +66,16 @@ public final class NetconfClientSessionNegotiatorFactory {
     private final @NonNegative int maximumIncomingChunkSize;
     private final Set<String> clientCapabilities;
     private final long connectionTimeoutMillis;
-    private final Timer timer;
+    private final NetconfTimer timer;
     private final EXIParameters options;
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis) {
         this(timer, additionalHeader, connectionTimeoutMillis, DEFAULT_OPTIONS);
     }
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis,
                                                  final @NonNegative int maximumIncomingChunkSize) {
@@ -83,20 +83,20 @@ public final class NetconfClientSessionNegotiatorFactory {
             maximumIncomingChunkSize);
     }
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis, final Set<String> capabilities) {
         this(timer, additionalHeader, connectionTimeoutMillis, DEFAULT_OPTIONS, capabilities);
 
     }
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis, final EXIParameters exiOptions) {
         this(timer, additionalHeader, connectionTimeoutMillis, exiOptions, EXI_CLIENT_CAPABILITIES);
     }
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis, final EXIParameters exiOptions,
                                                  final Set<String> capabilities) {
@@ -104,7 +104,7 @@ public final class NetconfClientSessionNegotiatorFactory {
             NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE);
     }
 
-    public NetconfClientSessionNegotiatorFactory(final Timer timer,
+    public NetconfClientSessionNegotiatorFactory(final NetconfTimer timer,
                                                  final Optional<NetconfHelloMessageAdditionalHeader> additionalHeader,
                                                  final long connectionTimeoutMillis, final EXIParameters exiOptions,
                                                  final Set<String> capabilities,
index 26993e1fcb75bc3735af4685347e2fb0f37e30ae..142009b7ba50aa88efcdf10190b0629195118e66 100644 (file)
@@ -46,6 +46,7 @@ import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.shaded.sshd.client.auth.password.PasswordIdentityProvider;
 import org.opendaylight.netconf.shaded.sshd.server.auth.password.UserAuthPasswordFactory;
 import org.opendaylight.netconf.shaded.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
@@ -91,7 +92,8 @@ class NetconfClientFactoryImplTest {
     private static final String RSA = "RSA";
     private static final char[] EMPTY_SECRET = new char[0];
 
-    private static SSHTransportStackFactory serverTransportFactory;
+    private static SSHTransportStackFactory SERVER_FACTORY;
+    private static DefaultNetconfTimer TIMER;
 
     @Mock
     private NetconfClientSessionListener sessionListener;
@@ -104,20 +106,21 @@ class NetconfClientFactoryImplTest {
     private TcpServerGrouping tcpServerParams;
     private TcpClientGrouping tcpClientParams;
 
-
     @BeforeAll
     static void beforeAll() {
-        serverTransportFactory = new SSHTransportStackFactory("server", 0);
+        SERVER_FACTORY = new SSHTransportStackFactory("server", 0);
+        TIMER = new DefaultNetconfTimer();
     }
 
     @AfterAll
     static void afterAll() {
-        serverTransportFactory.close();
+        SERVER_FACTORY.close();
+        TIMER.close();
     }
 
     @BeforeEach
     void beforeEach() throws Exception {
-        factory = new NetconfClientFactoryImpl();
+        factory = new NetconfClientFactoryImpl(TIMER);
         doNothing().when(serverTransportListener).onTransportChannelEstablished(any());
 
         // create temp socket to get available port for test
@@ -141,7 +144,7 @@ class NetconfClientFactoryImplTest {
     @Test
     void tcpClient() throws Exception {
         final var server = TCPServer.listen(serverTransportListener,
-            serverTransportFactory.newServerBootstrap(), tcpServerParams).get(1, TimeUnit.SECONDS);
+            SERVER_FACTORY.newServerBootstrap(), tcpServerParams).get(1, TimeUnit.SECONDS);
         try {
             final var clientConfig = NetconfClientConfigurationBuilder.create()
                 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP)
@@ -164,7 +167,7 @@ class NetconfClientFactoryImplTest {
         final var serverContext = SslContextBuilder.forServer(keyMgr).trustManager(trustMgr).build();
         final var clientContext = SslContextBuilder.forClient().keyManager(keyMgr).trustManager(trustMgr).build();
 
-        final var server = TLSServer.listen(serverTransportListener, serverTransportFactory.newServerBootstrap(),
+        final var server = TLSServer.listen(serverTransportListener, SERVER_FACTORY.newServerBootstrap(),
             tcpServerParams, channel -> serverContext.newHandler(channel.alloc())).get(1, TimeUnit.SECONDS);
         try {
             final var clientConfig = NetconfClientConfigurationBuilder.create()
@@ -211,7 +214,7 @@ class NetconfClientFactoryImplTest {
         doReturn(null).when(sshServerParams).getTransportParams();
         doReturn(null).when(sshServerParams).getKeepalives();
 
-        final var server = serverTransportFactory.listenServer("netconf", serverTransportListener, tcpServerParams,
+        final var server = SERVER_FACTORY.listenServer("netconf", serverTransportListener, tcpServerParams,
             sshServerParams).get(10, TimeUnit.SECONDS);
 
         try {
@@ -278,7 +281,7 @@ class NetconfClientFactoryImplTest {
                 new org.opendaylight.netconf.shaded.sshd.client.auth.password.UserAuthPasswordFactory()));
         };
 
-        final var server = serverTransportFactory.listenServer("netconf", serverTransportListener, tcpServerParams,
+        final var server = SERVER_FACTORY.listenServer("netconf", serverTransportListener, tcpServerParams,
             null, serverConfigurator).get(10, TimeUnit.SECONDS);
         try {
             final var clientConfig = NetconfClientConfigurationBuilder.create()
index 34fa1f325662e7a97f76f5375f852a826ec144fb..cab7ec382ab6caf759f36f1c16f4fe293a3a5112 100644 (file)
@@ -12,18 +12,17 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
 import io.netty.channel.Channel;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import java.util.Optional;
 import org.junit.Test;
 import org.opendaylight.netconf.api.NetconfSessionListenerFactory;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 
 public class NetconfClientSessionNegotiatorFactoryTest {
     @Test
     public void testGetSessionNegotiator() throws Exception {
         NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
-        Timer timer = new HashedWheelTimer();
+        final var timer = new DefaultNetconfTimer();
         NetconfSessionListenerFactory<NetconfClientSessionListener> listenerFactory =
                 mock(NetconfSessionListenerFactory.class);
         doReturn(sessionListener).when(listenerFactory).getSessionListener();
index 9d8a0a72a908105769c443a4808b536f5cb5fed5..ffb32f353b06731fa49342b3cd70a6f9c908fc13 100644 (file)
@@ -29,8 +29,6 @@ import io.netty.channel.ChannelPromise;
 import io.netty.channel.EventLoop;
 import io.netty.handler.codec.MessageToByteEncoder;
 import io.netty.handler.ssl.SslHandler;
-import io.netty.util.HashedWheelTimer;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.GenericFutureListener;
 import io.netty.util.concurrent.Promise;
 import java.io.InputStream;
@@ -42,6 +40,7 @@ import org.opendaylight.netconf.api.messages.HelloMessage;
 import org.opendaylight.netconf.api.messages.NetconfMessage;
 import org.opendaylight.netconf.api.messages.RpcMessage;
 import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.nettyutil.handler.ChunkedFramingMechanismEncoder;
 import org.opendaylight.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
 import org.opendaylight.netconf.nettyutil.handler.NetconfXMLToHelloMessageDecoder;
@@ -133,7 +132,7 @@ public class NetconfClientSessionNegotiatorTest {
 
         long timeout = 10L;
         NetconfClientSessionListener sessionListener = mock(NetconfClientSessionListener.class);
-        Timer timer = new HashedWheelTimer();
+        var timer = new DefaultNetconfTimer();
         return new NetconfClientSessionNegotiator(helloMessage, startExi, promise, channel, timer, sessionListener,
             timeout, 16384);
     }
diff --git a/protocol/netconf-common/pom.xml b/protocol/netconf-common/pom.xml
new file mode 100644 (file)
index 0000000..153d2a8
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2024 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>netconf-parent</artifactId>
+        <version>7.0.0-SNAPSHOT</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>netconf-common</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+    <description>Shared NETCONF protocol components</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.guicedee.services</groupId>
+            <artifactId>javax.inject</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jdt</groupId>
+            <artifactId>org.eclipse.jdt.annotation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.component.annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.metatype.annotations</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/protocol/netconf-common/src/main/java/module-info.java b/protocol/netconf-common/src/main/java/module-info.java
new file mode 100644 (file)
index 0000000..30f56e8
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2024 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
+ */
+module org.opendaylight.netconf.common {
+    exports org.opendaylight.netconf.common;
+    exports org.opendaylight.netconf.common.impl;
+
+    requires transitive io.netty.common;
+    requires com.google.common;
+    requires org.slf4j;
+
+    // Annotation-only dependencies
+    requires static transitive java.annotation;
+    requires static transitive javax.inject;
+    requires static transitive org.eclipse.jdt.annotation;
+    requires static org.osgi.service.component.annotations;
+    requires static org.osgi.service.metatype.annotations;
+}
diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/NetconfTimer.java
new file mode 100644 (file)
index 0000000..2abb3e7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 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.common;
+
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * A NETCONF-specific equivalent of {@link Timer}. It specifically excludes {@link Timer#stop()} from the API surface.
+ */
+@NonNullByDefault
+public interface NetconfTimer {
+    /**
+     * Schedules the specified {@link TimerTask} for one-time execution after the specified delay.
+     * See {@link Timer#newTimeout(TimerTask, long, TimeUnit)}.
+     *
+     * @param task a TimerTask
+     * @param delay delay to apply
+     * @param unit a TimeUnit
+     * @return a handle which is associated with the specified task
+     * @throws NullPointerException if any argument is {@code null}
+     * @throws IllegalStateException if this timer has been stopped already
+     * @throws RejectedExecutionException if the pending timeouts are too many and creating new timeout can cause
+     *                                    instability in the system
+     */
+    Timeout newTimeout(TimerTask task, long delay, TimeUnit unit);
+}
diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/impl/DefaultNetconfTimer.java
new file mode 100644 (file)
index 0000000..213e984
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2024 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.common.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import io.netty.util.HashedWheelTimer;
+import io.netty.util.Timeout;
+import io.netty.util.TimerTask;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.netconf.common.NetconfTimer;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Default {@link NetconfTimer}, delegating to a {@link HashedWheelTimer}.
+ */
+@Singleton
+@Component(service = NetconfTimer.class, configurationPid = "org.opendaylight.netconf.timer")
+@Designate(ocd = DefaultNetconfTimer.Configuration.class)
+public final class DefaultNetconfTimer implements NetconfTimer, AutoCloseable {
+    /**
+     * Configuration of {@link DefaultNetconfTimer}.
+     */
+    @ObjectClassDefinition
+    public @interface Configuration {
+        /**
+         * Return the duration of each timer tick in milliseconds.
+         *
+         * @return the duration of each timer tick in milliseconds
+         */
+        @AttributeDefinition(description = "Duration of each timer tick in milliseconds", min = "1")
+        long tick$_$duration$_$_millis() default 100;
+
+        /**
+         * Return the size of the timer wheel.
+         *
+         * @return the size of the timer wheel
+         */
+        @AttributeDefinition(description = "The size of the timer wheel", min = "1", max = "1073741824")
+        int ticks$_$per$_$wheel() default 512;
+    }
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultNetconfTimer.class);
+    private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder()
+        .setNameFormat("netconf-timer-%d")
+        .setDaemon(true)
+        .build();
+
+    private HashedWheelTimer delegate;
+
+    /**
+     * Default constructor. Uses default values for both tick duration and wheel size.
+     */
+    @Inject
+    public DefaultNetconfTimer() {
+        this(100, TimeUnit.MILLISECONDS, 512);
+    }
+
+    /**
+     * Low-level constructor.
+     *
+     * @param tickDuration the duration between tick
+     * @param unit the time unit of the {@code tickDuration}
+     * @param ticksPerWheel the size of the wheel
+     */
+    public DefaultNetconfTimer(final long tickDuration, final TimeUnit unit, final int ticksPerWheel) {
+        delegate = new HashedWheelTimer(THREAD_FACTORY, tickDuration, unit, ticksPerWheel);
+        LOG.info("NETCONF timer started");
+    }
+
+    /**
+     * OSGi constructor. Uses values from supplied {@link Configuration}.
+     *
+     * @param config the configuration
+     */
+    @Activate
+    public DefaultNetconfTimer(final Configuration config) {
+        this(config.tick$_$duration$_$_millis(), TimeUnit.MILLISECONDS, config.ticks$_$per$_$wheel());
+    }
+
+    @Override
+    public Timeout newTimeout(final TimerTask task, final long delay, final TimeUnit unit) {
+        final var local = delegate;
+        if (local == null) {
+            throw new IllegalStateException("Timer has already been stopped");
+        }
+        return local.newTimeout(requireNonNull(task), delay, requireNonNull(unit));
+    }
+
+    @Deactivate
+    @PreDestroy
+    @Override
+    public void close() {
+        if (delegate != null) {
+            delegate.stop();
+            delegate = null;
+            LOG.info("NETCONF timer started");
+        }
+    }
+}
diff --git a/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java b/protocol/netconf-common/src/main/java/org/opendaylight/netconf/common/package-info.java
new file mode 100644 (file)
index 0000000..66034ad
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2024 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
+ */
+/**
+ * Components shared between NETCONF client and NETCONF server.
+ */
+package org.opendaylight.netconf.common;
\ No newline at end of file
index 01cb0e6a9f5fc0c76f062fc3ac117ff30de4846d..3fe894a68919a9e08195aa45a6d601d35dba51bb 100644 (file)
@@ -11,7 +11,6 @@ import static java.util.Objects.requireNonNull;
 
 import io.netty.channel.Channel;
 import io.netty.channel.local.LocalAddress;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
@@ -22,6 +21,7 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.netconf.api.NetconfDocumentedException;
 import org.opendaylight.netconf.api.messages.HelloMessage;
 import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
 import org.slf4j.Logger;
@@ -35,7 +35,7 @@ public final class NetconfServerSessionNegotiator
     private final @NonNull SessionIdType sessionId;
 
     NetconfServerSessionNegotiator(final HelloMessage hello, final SessionIdType sessionId,
-            final Promise<NetconfServerSession> promise, final Channel channel, final Timer timer,
+            final Promise<NetconfServerSession> promise, final Channel channel, final NetconfTimer timer,
             final NetconfServerSessionListener sessionListener, final long connectionTimeoutMillis,
             final @NonNegative int maximumIncomingChunkSize) {
         super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis,
index 444533c3caaa0afebe5909dcbacd291101136ff1..5e32aaa55c48885a10718128d77336dc964e37b7 100644 (file)
@@ -13,7 +13,6 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import io.netty.channel.Channel;
-import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
 import java.net.SocketAddress;
 import java.util.HashSet;
@@ -22,6 +21,7 @@ import org.checkerframework.checker.index.qual.NonNegative;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.api.messages.HelloMessage;
+import org.opendaylight.netconf.common.NetconfTimer;
 import org.opendaylight.netconf.nettyutil.NetconfSessionNegotiator;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
 import org.opendaylight.netconf.server.api.monitoring.NetconfMonitoringService;
@@ -32,21 +32,21 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.re
 
 // non-final for testing and netconf-testtool (for some reason)
 public class NetconfServerSessionNegotiatorFactory {
-    public static final Set<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
+    public static final ImmutableSet<String> DEFAULT_BASE_CAPABILITIES = ImmutableSet.of(
         CapabilityURN.BASE,
         CapabilityURN.BASE_1_1,
         CapabilityURN.EXI,
         CapabilityURN.NOTIFICATION);
 
     private final @NonNegative int maximumIncomingChunkSize;
-    private final Timer timer;
+    private final NetconfTimer timer;
     private final SessionIdProvider idProvider;
     private final NetconfOperationServiceFactory aggregatedOpService;
     private final long connectionTimeoutMillis;
     private final NetconfMonitoringService monitoringService;
     private final Set<String> baseCapabilities;
 
-    protected NetconfServerSessionNegotiatorFactory(final Timer timer,
+    protected NetconfServerSessionNegotiatorFactory(final NetconfTimer timer,
             final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider,
             final long connectionTimeoutMillis,  final NetconfMonitoringService monitoringService,
             final Set<String> baseCapabilities) {
@@ -54,11 +54,11 @@ public class NetconfServerSessionNegotiatorFactory {
             NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE);
     }
 
-    private NetconfServerSessionNegotiatorFactory(final Timer timer,
+    private NetconfServerSessionNegotiatorFactory(final NetconfTimer timer,
             final NetconfOperationServiceFactory netconfOperationProvider, final SessionIdProvider idProvider,
             final long connectionTimeoutMillis, final NetconfMonitoringService monitoringService,
             final Set<String> baseCapabilities, final @NonNegative int maximumIncomingChunkSize) {
-        this.timer = timer;
+        this.timer = requireNonNull(timer);
         aggregatedOpService = netconfOperationProvider;
         this.idProvider = idProvider;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
@@ -124,7 +124,7 @@ public class NetconfServerSessionNegotiatorFactory {
     public static final class Builder {
         private @NonNegative int maximumIncomingChunkSize =
             NetconfSessionNegotiator.DEFAULT_MAXIMUM_INCOMING_CHUNK_SIZE;
-        private Timer timer;
+        private NetconfTimer timer;
         private SessionIdProvider idProvider;
         private NetconfOperationServiceFactory aggregatedOpService;
         private long connectionTimeoutMillis;
@@ -135,8 +135,8 @@ public class NetconfServerSessionNegotiatorFactory {
             // Hidden on purpose
         }
 
-        public Builder setTimer(final Timer timer) {
-            this.timer = timer;
+        public Builder setTimer(final NetconfTimer timer) {
+            this.timer = requireNonNull(timer);
             return this;
         }
 
index 74f3e2e5ec8bde59909bed5c23b9a37baa008919..1922cd675cb0ceac183780671a529352c8f1f36e 100644 (file)
@@ -17,7 +17,6 @@ import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.lenient;
 import static org.opendaylight.netconf.server.NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES;
 
-import io.netty.util.HashedWheelTimer;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
@@ -36,7 +35,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -53,6 +51,7 @@ import org.opendaylight.netconf.client.NetconfClientFactoryImpl;
 import org.opendaylight.netconf.client.NetconfMessageUtil;
 import org.opendaylight.netconf.client.SimpleNetconfClientSessionListener;
 import org.opendaylight.netconf.client.conf.NetconfClientConfigurationBuilder;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessageProvider;
 import org.opendaylight.netconf.server.api.SessionIdProvider;
 import org.opendaylight.netconf.server.api.monitoring.Capability;
@@ -103,11 +102,11 @@ public class ConcurrentClientsTest {
     private static int serverPort;
     private static TcpServerGrouping serverParams;
     private static TcpClientGrouping clientParams;
+    private static DefaultNetconfTimer timer;
 
     private static NetconfMessage getConfigMessage;
     private static NetconfMessage clientHelloMessage;
 
-    private HashedWheelTimer hashedWheelTimer;
     private BootstrapFactory serverBootstrapFactory;
     private NetconfClientFactory clientFactory;
     private TCPServer server;
@@ -120,6 +119,7 @@ public class ConcurrentClientsTest {
 
     @BeforeAll
     public static void beforeAll() throws Exception {
+        timer = new DefaultNetconfTimer();
         clientExecutor = Executors.newFixedThreadPool(CONCURRENCY, new ThreadFactory() {
             int index = 1;
 
@@ -151,11 +151,7 @@ public class ConcurrentClientsTest {
     @AfterAll
     static void afterAll() {
         clientExecutor.shutdownNow();
-    }
-
-    @BeforeEach
-    void beforeEach() {
-        hashedWheelTimer = new HashedWheelTimer();
+        timer.close();
     }
 
     void startServer(final int threads, final Set<String> serverCapabilities) throws Exception {
@@ -175,7 +171,7 @@ public class ConcurrentClientsTest {
 
         serverBootstrapFactory = new BootstrapFactory("server", threads);
         server = TCPServer.listen(new ServerTransportInitializer(NetconfServerSessionNegotiatorFactory.builder()
-            .setTimer(hashedWheelTimer)
+            .setTimer(timer)
             .setAggregatedOpService(factoriesListener)
             .setIdProvider(ID_PROVIDER)
             .setConnectionTimeoutMillis(TIMEOUT)
@@ -187,7 +183,6 @@ public class ConcurrentClientsTest {
 
     @AfterEach
     void afterEach() throws Exception {
-        hashedWheelTimer.stop();
         server.shutdown().get(TIMEOUT, MILLISECONDS);
         serverBootstrapFactory.close();
         if (clientFactory != null) {
@@ -203,7 +198,7 @@ public class ConcurrentClientsTest {
 
         startServer(threads, serverCaps);
         clientFactory = clientClass == NetconfClientRunnable.class
-            ? new NetconfClientFactoryImpl(new SSHTransportStackFactory("client", threads)) : null;
+            ? new NetconfClientFactoryImpl(timer, new SSHTransportStackFactory("client", threads)) : null;
 
         final var futures = new ArrayList<Future<?>>(CONCURRENCY);
         for (int i = 0; i < CONCURRENCY; i++) {
index 17726d5ae72f1c9c505b326ea79aac07cafb5c80..e4c6aa034920464811e98ce931ee9ec0a5133b2d 100644 (file)
@@ -31,6 +31,7 @@
     <modules>
         <module>netconf-api</module>
         <module>netconf-client</module>
+        <module>netconf-common</module>
         <module>netconf-server</module>
         <module>netconf-test-util</module>
         <module>restconf-api</module>