2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.topology.spi;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.ListeningExecutorService;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import io.netty.util.concurrent.EventExecutor;
20 import java.math.BigDecimal;
21 import java.net.InetSocketAddress;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.List;
27 import java.util.Optional;
28 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
29 import org.opendaylight.controller.config.threadpool.ScheduledThreadPool;
30 import org.opendaylight.controller.config.threadpool.ThreadPool;
31 import org.opendaylight.mdsal.binding.api.DataBroker;
32 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
33 import org.opendaylight.netconf.api.NetconfMessage;
34 import org.opendaylight.netconf.client.NetconfClientDispatcher;
35 import org.opendaylight.netconf.client.NetconfClientSessionListener;
36 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
37 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
38 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
39 import org.opendaylight.netconf.nettyutil.ReconnectStrategyFactory;
40 import org.opendaylight.netconf.nettyutil.TimedReconnectStrategyFactory;
41 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
42 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
43 import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
44 import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
45 import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
46 import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
47 import org.opendaylight.netconf.sal.connect.netconf.LibraryModulesSchemas;
48 import org.opendaylight.netconf.sal.connect.netconf.NetconfDevice.SchemaResourcesDTO;
49 import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceBuilder;
50 import org.opendaylight.netconf.sal.connect.netconf.SchemalessNetconfDevice;
51 import org.opendaylight.netconf.sal.connect.netconf.auth.DatastoreBackedPublicKeyAuth;
52 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
53 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
54 import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
55 import org.opendaylight.netconf.sal.connect.netconf.listener.UserPreferences;
56 import org.opendaylight.netconf.sal.connect.netconf.sal.KeepaliveSalFacade;
57 import org.opendaylight.netconf.sal.connect.netconf.sal.NetconfKeystoreAdapter;
58 import org.opendaylight.netconf.sal.connect.netconf.schema.YangLibrarySchemaYangSourceProvider;
59 import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.BaseNetconfSchemas;
60 import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
61 import org.opendaylight.netconf.sal.connect.util.SslHandlerFactoryImpl;
62 import org.opendaylight.netconf.topology.api.NetconfTopology;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.optional.rev190614.NetconfNodeAugmentedOptional;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.Protocol.Name;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.KeyAuth;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPw;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPwUnencrypted;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.key.auth.KeyBased;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.LoginPassword;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencrypted;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.schema.storage.YangLibrary;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
81 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
82 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
83 import org.opendaylight.yangtools.yang.model.repo.spi.PotentialSchemaSource;
84 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistration;
85 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
89 public abstract class AbstractNetconfTopology implements NetconfTopology {
90 private static final Logger LOG = LoggerFactory.getLogger(AbstractNetconfTopology.class);
92 protected static final long DEFAULT_REQUEST_TIMEOUT_MILLIS = 60000L;
93 protected static final int DEFAULT_KEEPALIVE_DELAY = 0;
94 protected static final boolean DEFAULT_RECONNECT_ON_CHANGED_SCHEMA = false;
95 protected static final int DEFAULT_CONCURRENT_RPC_LIMIT = 0;
96 private static final boolean DEFAULT_IS_TCP_ONLY = false;
97 private static final int DEFAULT_MAX_CONNECTION_ATTEMPTS = 0;
98 private static final int DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS = 2000;
99 private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 20000L;
100 private static final BigDecimal DEFAULT_SLEEP_FACTOR = new BigDecimal(1.5);
102 private final NetconfClientDispatcher clientDispatcher;
103 private final EventExecutor eventExecutor;
104 private final DeviceActionFactory deviceActionFactory;
105 private final NetconfKeystoreAdapter keystoreAdapter;
106 private final SchemaResourceManager schemaManager;
107 private final BaseNetconfSchemas baseSchemas;
109 protected final ScheduledThreadPool keepaliveExecutor;
110 protected final ListeningExecutorService processingExecutor;
111 protected final DataBroker dataBroker;
112 protected final DOMMountPointService mountPointService;
113 protected final String topologyId;
114 protected String privateKeyPath;
115 protected String privateKeyPassphrase;
116 protected final AAAEncryptionService encryptionService;
117 protected final HashMap<NodeId, NetconfConnectorDTO> activeConnectors = new HashMap<>();
120 protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher,
121 final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor,
122 final ThreadPool processingExecutor, final SchemaResourceManager schemaManager,
123 final DataBroker dataBroker, final DOMMountPointService mountPointService,
124 final AAAEncryptionService encryptionService,
125 final DeviceActionFactory deviceActionFactory,
126 final BaseNetconfSchemas baseSchemas) {
127 this.topologyId = topologyId;
128 this.clientDispatcher = clientDispatcher;
129 this.eventExecutor = eventExecutor;
130 this.keepaliveExecutor = keepaliveExecutor;
131 this.processingExecutor = MoreExecutors.listeningDecorator(processingExecutor.getExecutor());
132 this.schemaManager = requireNonNull(schemaManager);
133 this.deviceActionFactory = deviceActionFactory;
134 this.dataBroker = dataBroker;
135 this.mountPointService = mountPointService;
136 this.encryptionService = encryptionService;
137 this.baseSchemas = requireNonNull(baseSchemas);
139 this.keystoreAdapter = new NetconfKeystoreAdapter(dataBroker);
143 public ListenableFuture<NetconfDeviceCapabilities> connectNode(final NodeId nodeId, final Node configNode) {
144 LOG.info("Connecting RemoteDevice{{}} , with config {}", nodeId, hideCredentials(configNode));
145 return setupConnection(nodeId, configNode);
149 * Hiding of private credentials from node configuration (credentials data is replaced by asterisks).
151 * @param nodeConfiguration Node configuration container.
152 * @return String representation of node configuration with credentials replaced by asterisks.
155 public static String hideCredentials(final Node nodeConfiguration) {
156 final NetconfNode netconfNodeAugmentation = nodeConfiguration.augmentation(NetconfNode.class);
157 final String nodeCredentials = netconfNodeAugmentation.getCredentials().toString();
158 final String nodeConfigurationString = nodeConfiguration.toString();
159 return nodeConfigurationString.replace(nodeCredentials, "***");
163 public ListenableFuture<Void> disconnectNode(final NodeId nodeId) {
164 LOG.debug("Disconnecting RemoteDevice{{}}", nodeId.getValue());
166 final NetconfConnectorDTO connectorDTO = activeConnectors.remove(nodeId);
167 if (connectorDTO == null) {
168 return Futures.immediateFailedFuture(
169 new IllegalStateException("Unable to disconnect device that is not connected"));
172 connectorDTO.close();
173 return Futures.immediateFuture(null);
176 protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
177 final Node configNode) {
178 final NetconfNode netconfNode = configNode.augmentation(NetconfNode.class);
179 final NetconfNodeAugmentedOptional nodeOptional = configNode.augmentation(NetconfNodeAugmentedOptional.class);
181 requireNonNull(netconfNode.getHost());
182 requireNonNull(netconfNode.getPort());
184 final NetconfConnectorDTO deviceCommunicatorDTO = createDeviceCommunicator(nodeId, netconfNode, nodeOptional);
185 final NetconfDeviceCommunicator deviceCommunicator = deviceCommunicatorDTO.getCommunicator();
186 final NetconfClientSessionListener netconfClientSessionListener = deviceCommunicatorDTO.getSessionListener();
187 final NetconfReconnectingClientConfiguration clientConfig =
188 getClientConfig(netconfClientSessionListener, netconfNode);
189 final ListenableFuture<NetconfDeviceCapabilities> future =
190 deviceCommunicator.initializeRemoteConnection(clientDispatcher, clientConfig);
192 activeConnectors.put(nodeId, deviceCommunicatorDTO);
194 Futures.addCallback(future, new FutureCallback<NetconfDeviceCapabilities>() {
196 public void onSuccess(final NetconfDeviceCapabilities result) {
197 LOG.debug("Connector for {} started succesfully", nodeId.getValue());
201 public void onFailure(final Throwable throwable) {
202 LOG.error("Connector for {} failed", nodeId.getValue(), throwable);
203 // remove this node from active connectors?
205 }, MoreExecutors.directExecutor());
210 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node) {
211 return createDeviceCommunicator(nodeId, node, null);
214 protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, final NetconfNode node,
215 final NetconfNodeAugmentedOptional nodeOptional) {
216 //setup default values since default value is not supported in mdsal
217 final long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null
218 ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis().toJava();
219 final long keepaliveDelay = node.getKeepaliveDelay() == null
220 ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay().toJava();
222 final IpAddress ipAddress = node.getHost().getIpAddress();
223 final InetSocketAddress address = new InetSocketAddress(ipAddress.getIpv4Address() != null
224 ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue(),
225 node.getPort().getValue().toJava());
226 final RemoteDeviceId remoteDeviceId = new RemoteDeviceId(nodeId.getValue(), address);
228 RemoteDeviceHandler<NetconfSessionPreferences> salFacade = createSalFacade(remoteDeviceId);
230 if (keepaliveDelay > 0) {
231 LOG.warn("Adding keepalive facade, for device {}", nodeId);
232 salFacade = new KeepaliveSalFacade(remoteDeviceId, salFacade, this.keepaliveExecutor.getExecutor(),
233 keepaliveDelay, defaultRequestTimeoutMillis);
236 final RemoteDevice<NetconfSessionPreferences, NetconfMessage, NetconfDeviceCommunicator> device;
237 final List<SchemaSourceRegistration<?>> yanglibRegistrations;
238 if (node.isSchemaless()) {
239 device = new SchemalessNetconfDevice(baseSchemas, remoteDeviceId, salFacade);
240 yanglibRegistrations = List.of();
242 final boolean reconnectOnChangedSchema = node.isReconnectOnChangedSchema() == null
243 ? DEFAULT_RECONNECT_ON_CHANGED_SCHEMA : node.isReconnectOnChangedSchema();
245 final SchemaResourcesDTO resources = schemaManager.getSchemaResources(node, nodeId.getValue());
246 device = new NetconfDeviceBuilder()
247 .setReconnectOnSchemasChange(reconnectOnChangedSchema)
248 .setSchemaResourcesDTO(resources)
249 .setGlobalProcessingExecutor(this.processingExecutor)
250 .setId(remoteDeviceId)
251 .setSalFacade(salFacade)
253 .setEventExecutor(eventExecutor)
254 .setNodeOptional(nodeOptional)
255 .setDeviceActionFactory(deviceActionFactory)
256 .setBaseSchemas(baseSchemas)
258 yanglibRegistrations = registerDeviceSchemaSources(remoteDeviceId, nodeId, node, resources);
261 final Optional<UserPreferences> userCapabilities = getUserCapabilities(node);
262 final int rpcMessageLimit = node.getConcurrentRpcLimit() == null ? DEFAULT_CONCURRENT_RPC_LIMIT
263 : node.getConcurrentRpcLimit().toJava();
265 if (rpcMessageLimit < 1) {
266 LOG.info("Concurrent rpc limit is smaller than 1, no limit will be enforced for device {}", remoteDeviceId);
269 NetconfDeviceCommunicator netconfDeviceCommunicator =
270 userCapabilities.isPresent() ? new NetconfDeviceCommunicator(remoteDeviceId, device,
271 userCapabilities.get(), rpcMessageLimit)
272 : new NetconfDeviceCommunicator(remoteDeviceId, device, rpcMessageLimit);
274 if (salFacade instanceof KeepaliveSalFacade) {
275 ((KeepaliveSalFacade)salFacade).setListener(netconfDeviceCommunicator);
278 return new NetconfConnectorDTO(netconfDeviceCommunicator, salFacade, yanglibRegistrations);
281 private List<SchemaSourceRegistration<?>> registerDeviceSchemaSources(final RemoteDeviceId remoteDeviceId,
282 final NodeId nodeId, final NetconfNode node, final SchemaResourcesDTO resources) {
283 final YangLibrary yangLibrary = node.getYangLibrary();
284 if (yangLibrary != null) {
285 final Uri uri = yangLibrary.getYangLibraryUrl();
287 final List<SchemaSourceRegistration<?>> registrations = new ArrayList<>();
288 final String yangLibURL = uri.getValue();
289 final SchemaSourceRegistry schemaRegistry = resources.getSchemaRegistry();
291 // pre register yang library sources as fallback schemas to schema registry
292 final LibraryModulesSchemas schemas;
293 final String yangLibUsername = yangLibrary.getUsername();
294 final String yangLigPassword = yangLibrary.getPassword();
295 if (yangLibUsername != null && yangLigPassword != null) {
296 schemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
298 schemas = LibraryModulesSchemas.create(yangLibURL);
301 for (final Map.Entry<SourceIdentifier, URL> entry : schemas.getAvailableModels().entrySet()) {
302 registrations.add(schemaRegistry.registerSchemaSource(new YangLibrarySchemaYangSourceProvider(
303 remoteDeviceId, schemas.getAvailableModels()),
304 PotentialSchemaSource.create(entry.getKey(), YangTextSchemaSource.class,
305 PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
307 return registrations;
315 * Sets the private key path from location specified in configuration file using blueprint.
317 public void setPrivateKeyPath(final String privateKeyPath) {
318 this.privateKeyPath = privateKeyPath;
322 * Sets the private key passphrase from location specified in configuration file using blueprint.
324 public void setPrivateKeyPassphrase(final String privateKeyPassphrase) {
325 this.privateKeyPassphrase = privateKeyPassphrase;
328 public NetconfReconnectingClientConfiguration getClientConfig(final NetconfClientSessionListener listener,
329 final NetconfNode node) {
331 //setup default values since default value is not supported in mdsal
332 final long clientConnectionTimeoutMillis = node.getConnectionTimeoutMillis() == null
333 ? DEFAULT_CONNECTION_TIMEOUT_MILLIS : node.getConnectionTimeoutMillis().toJava();
334 final long maxConnectionAttempts = node.getMaxConnectionAttempts() == null
335 ? DEFAULT_MAX_CONNECTION_ATTEMPTS : node.getMaxConnectionAttempts().toJava();
336 final int betweenAttemptsTimeoutMillis = node.getBetweenAttemptsTimeoutMillis() == null
337 ? DEFAULT_BETWEEN_ATTEMPTS_TIMEOUT_MILLIS : node.getBetweenAttemptsTimeoutMillis().toJava();
338 final boolean useTcp = node.isTcpOnly() == null ? DEFAULT_IS_TCP_ONLY : node.isTcpOnly();
339 final BigDecimal sleepFactor = node.getSleepFactor() == null ? DEFAULT_SLEEP_FACTOR : node.getSleepFactor();
341 final InetSocketAddress socketAddress = getSocketAddress(node.getHost(), node.getPort().getValue().toJava());
343 final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(eventExecutor,
344 maxConnectionAttempts, betweenAttemptsTimeoutMillis, sleepFactor);
346 final NetconfReconnectingClientConfigurationBuilder reconnectingClientConfigurationBuilder;
347 final Protocol protocol = node.getProtocol();
349 reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
350 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TCP)
351 .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
352 } else if (protocol == null || protocol.getName() == Name.SSH) {
353 reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
354 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
355 .withAuthHandler(getHandlerFromCredentials(node.getCredentials()));
356 } else if (protocol.getName() == Name.TLS) {
357 reconnectingClientConfigurationBuilder = NetconfReconnectingClientConfigurationBuilder.create()
358 .withSslHandlerFactory(new SslHandlerFactoryImpl(keystoreAdapter, protocol.getSpecification()))
359 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.TLS);
361 throw new IllegalStateException("Unsupported protocol type: " + protocol.getName());
364 if (node.getOdlHelloMessageCapabilities() != null) {
365 reconnectingClientConfigurationBuilder
366 .withOdlHelloCapabilities(node.getOdlHelloMessageCapabilities().getCapability());
369 return reconnectingClientConfigurationBuilder
370 .withAddress(socketAddress)
371 .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
372 .withReconnectStrategy(sf.createReconnectStrategy())
373 .withConnectStrategyFactory(sf)
374 .withSessionListener(listener)
378 private AuthenticationHandler getHandlerFromCredentials(final Credentials credentials) {
379 if (credentials instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
380 .rev150114.netconf.node.credentials.credentials.LoginPassword) {
381 final org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
382 .rev150114.netconf.node.credentials.credentials.LoginPassword loginPassword
383 = (org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology
384 .rev150114.netconf.node.credentials.credentials.LoginPassword) credentials;
385 return new LoginPasswordHandler(loginPassword.getUsername(), loginPassword.getPassword());
387 if (credentials instanceof LoginPwUnencrypted) {
388 final LoginPasswordUnencrypted loginPassword =
389 ((LoginPwUnencrypted) credentials).getLoginPasswordUnencrypted();
390 return new LoginPasswordHandler(loginPassword.getUsername(), loginPassword.getPassword());
392 if (credentials instanceof LoginPw) {
393 final LoginPassword loginPassword = ((LoginPw) credentials).getLoginPassword();
394 return new LoginPasswordHandler(loginPassword.getUsername(),
395 encryptionService.decrypt(loginPassword.getPassword()));
397 if (credentials instanceof KeyAuth) {
398 final KeyBased keyPair = ((KeyAuth) credentials).getKeyBased();
399 return new DatastoreBackedPublicKeyAuth(keyPair.getUsername(), keyPair.getKeyId(),
400 keystoreAdapter, encryptionService);
402 throw new IllegalStateException("Unsupported credential type: " + credentials.getClass());
405 protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(RemoteDeviceId id);
407 private static InetSocketAddress getSocketAddress(final Host host, final int port) {
408 if (host.getDomainName() != null) {
409 return new InetSocketAddress(host.getDomainName().getValue(), port);
412 final IpAddress ipAddress = host.getIpAddress();
413 final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue()
414 : ipAddress.getIpv6Address().getValue();
415 return new InetSocketAddress(ip, port);
418 private static Optional<UserPreferences> getUserCapabilities(final NetconfNode node) {
419 // if none of yang-module-capabilities or non-module-capabilities is specified
420 // just return absent
421 if (node.getYangModuleCapabilities() == null && node.getNonModuleCapabilities() == null) {
422 return Optional.empty();
425 final List<String> capabilities = new ArrayList<>();
427 boolean overrideYangModuleCaps = false;
428 if (node.getYangModuleCapabilities() != null) {
429 capabilities.addAll(node.getYangModuleCapabilities().getCapability());
430 overrideYangModuleCaps = node.getYangModuleCapabilities().isOverride();
433 //non-module capabilities should not exist in yang module capabilities
434 final NetconfSessionPreferences netconfSessionPreferences = NetconfSessionPreferences.fromStrings(capabilities);
435 Preconditions.checkState(netconfSessionPreferences.getNonModuleCaps().isEmpty(),
436 "List yang-module-capabilities/capability should contain only module based capabilities. "
437 + "Non-module capabilities used: " + netconfSessionPreferences.getNonModuleCaps());
439 boolean overrideNonModuleCaps = false;
440 if (node.getNonModuleCapabilities() != null) {
441 capabilities.addAll(node.getNonModuleCapabilities().getCapability());
442 overrideNonModuleCaps = node.getNonModuleCapabilities().isOverride();
445 return Optional.of(new UserPreferences(NetconfSessionPreferences
446 .fromStrings(capabilities, CapabilityOrigin.UserDefined), overrideYangModuleCaps, overrideNonModuleCaps));
449 protected static class NetconfConnectorDTO implements AutoCloseable {
450 private final List<SchemaSourceRegistration<?>> yanglibRegistrations;
451 private final NetconfDeviceCommunicator communicator;
452 private final RemoteDeviceHandler<NetconfSessionPreferences> facade;
454 public NetconfConnectorDTO(final NetconfDeviceCommunicator communicator,
455 final RemoteDeviceHandler<NetconfSessionPreferences> facade,
456 final List<SchemaSourceRegistration<?>> yanglibRegistrations) {
457 this.communicator = communicator;
458 this.facade = facade;
459 this.yanglibRegistrations = yanglibRegistrations;
462 public NetconfDeviceCommunicator getCommunicator() {
466 public RemoteDeviceHandler<NetconfSessionPreferences> getFacade() {
470 public NetconfClientSessionListener getSessionListener() {
475 public void close() {
476 communicator.close();
478 yanglibRegistrations.forEach(SchemaSourceRegistration::close);