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;
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;
@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,
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) {
*/
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;
// 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,
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;
@Activate
@Inject
public IetfZeroTouchCallHomeServerProvider(
+ final @Reference NetconfTimer timer,
final @Reference CallHomeMountService mountService,
final @Reference CallHomeSshAuthProvider authProvider,
final @Reference CallHomeStatusRecorder statusRecorder,
.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);
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;
@Activate
@Inject
public NetconfCallHomeTlsService(
+ final @Reference NetconfTimer timer,
final @Reference CallHomeMountService mountService,
final @Reference CallHomeTlsAuthProvider authProvider,
final @Reference CallHomeStatusRecorder statusRecorder,
.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);
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;
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(
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;
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;
@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,
}
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,
@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);
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;
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;
@Mock
private NetconfClientFactory mockedClientFactory;
@Mock
- private Timer mockedTimer;
+ private NetconfTimer mockedTimer;
@Mock
private SchemaResourceManager mockedResourceManager;
@Mock
}
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,
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;
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;
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;
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,
@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,
@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,
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;
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;
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;
return schemaAssembler;
}
- public Timer getTimer() {
+ public NetconfTimer getTimer() {
return timer;
}
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;
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;
}
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;
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;
@Mock
private AAAEncryptionService mockEncryptionService;
@Mock
- private Timer mockTimer;
+ private NetconfTimer mockTimer;
@Mock
private DeviceActionFactory deviceActionFactory;
@Mock
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;
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;
@Mock
private Registration mockRpcReg;
@Mock
- private Timer timer;
+ private NetconfTimer timer;
@Mock
private ExecutorService processingService;
@Mock
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;
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;
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;
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) {
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;
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;
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;
@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,
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;
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;
// Core setup
@Mock
- private Timer timer;
+ private NetconfTimer timer;
@Mock
private SchemaResourceManager schemaManager;
@Mock
<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>
<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>
+++ /dev/null
-<?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>
*/
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;
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
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) {
}
@Override
- public void onTransportChannelFailed(@NonNull Throwable cause) {
+ public void onTransportChannelFailed(final Throwable cause) {
statusRecorder.onTransportChannelFailure(cause);
}
}
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;
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;
}
}
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);
- }
}
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;
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;
}
}
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
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;
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;
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 =
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)
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());
}
.withAuthProvider(authProvider)
.withSessionContextManager(contextManager)
.withStatusRecorder(statusRecorder)
+ .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT,
+ NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
.build();
SSHServer client1 = null;
shutdownClient(client2);
shutdownClient(client3);
shutdownClient(client4);
+ timer.close();
}
// verify disconnect reported
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;
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;
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;
// 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;
}
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)
.withAuthProvider(authProvider)
.withSessionContextManager(contextMgr)
.withStatusRecorder(statusRecorder)
+ .withNegotiationFactory(new NetconfClientSessionNegotiatorFactory(timer, Optional.empty(), TIMEOUT,
+ NetconfClientSessionNegotiatorFactory.DEFAULT_CLIENT_CAPABILITIES))
.withPort(serverPort).build();
TLSServer client1 = null;
shutdownClient(client1);
shutdownClient(client2);
shutdownClient(client3);
+ timer.close();
}
// validate disconnect reported
<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>
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;
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;
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;
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;
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;
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;
@Mock
private SslHandler sslHandler;
@Mock
- private Timer timer;
+ private NetconfTimer timer;
@Mock
private Timeout timeout;
private EmbeddedChannel channel;
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;
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;
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
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);
}
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;
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;
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;
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()));
}
*/
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;
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);
}
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;
}
}
- 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) {
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;
"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;
@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));
stopSimulator(sshDeviceSimulator);
sshDeviceSimulator = null;
clientFactory.close();
+ timer.close();
}
@ParameterizedTest(name = "Custom RPC -- RFC7950 {0}")
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;
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;
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;
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);
}
public KeepaliveSalFacade(final RemoteDeviceId deviceId, final RemoteDeviceHandler deviceHandler,
- final Timer timer) {
+ final NetconfTimer timer) {
this(deviceId, deviceHandler, timer, DEFAULT_DELAY, DEFAULT_TRANSACTION_TIMEOUT_MILLI);
}
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;
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;
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);
@AfterEach
void afterEach() {
- timer.stop();
+ timer.close();
}
/**
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;
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;
@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
<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>
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;
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();
}
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;
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;
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);
// 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);
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;
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;
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) {
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) {
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,
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;
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;
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
@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)
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()
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 {
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()
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();
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;
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;
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);
}
--- /dev/null
+<?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>
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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");
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
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;
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;
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,
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;
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;
// 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) {
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;
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;
// Hidden on purpose
}
- public Builder setTimer(final Timer timer) {
- this.timer = timer;
+ public Builder setTimer(final NetconfTimer timer) {
+ this.timer = requireNonNull(timer);
return this;
}
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;
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;
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;
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;
@BeforeAll
public static void beforeAll() throws Exception {
+ timer = new DefaultNetconfTimer();
clientExecutor = Executors.newFixedThreadPool(CONCURRENCY, new ThreadFactory() {
int index = 1;
@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 {
serverBootstrapFactory = new BootstrapFactory("server", threads);
server = TCPServer.listen(new ServerTransportInitializer(NetconfServerSessionNegotiatorFactory.builder()
- .setTimer(hashedWheelTimer)
+ .setTimer(timer)
.setAggregatedOpService(factoriesListener)
.setIdProvider(ID_PROVIDER)
.setConnectionTimeoutMillis(TIMEOUT)
@AfterEach
void afterEach() throws Exception {
- hashedWheelTimer.stop();
server.shutdown().get(TIMEOUT, MILLISECONDS);
serverBootstrapFactory.close();
if (clientFactory != null) {
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++) {
<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>