import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.sal.AbstractNetconfDataTreeService;
private final ActorRef masterActorRef;
private final ActorSystem actorSystem;
- private MountPointContext currentMountContext = null;
+ private NetconfDeviceSchema currentSchema = null;
private NetconfSessionPreferences netconfSessionPreferences = null;
private DOMRpcService deviceRpc = null;
private DOMDataBroker deviceDataBroker = null;
}
@Override
- public void onDeviceConnected(final MountPointContext mountContext,
+ public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences sessionPreferences,
final DOMRpcService domRpcService, final DOMActionService domActionService) {
deviceAction = domActionService;
LOG.debug("{}: YANG 1.1 actions are supported in clustered netconf topology, "
+ "DOMActionService exposed for the device", id);
- onDeviceConnected(mountContext, sessionPreferences, domRpcService);
+ onDeviceConnected(deviceSchema, sessionPreferences, domRpcService);
}
@Override
- public void onDeviceConnected(final MountPointContext mountContext,
+ public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences sessionPreferences,
final DOMRpcService domRpcService) {
- currentMountContext = mountContext;
+ currentSchema = requireNonNull(deviceSchema);
netconfSessionPreferences = sessionPreferences;
deviceRpc = domRpcService;
LOG.error("{}: CreateInitialMasterActorData to {} failed", id, masterActorRef, failure);
}
}, actorSystem.dispatcher());
-
}
@Override
public void onDeviceDisconnected() {
LOG.info("Device {} disconnected - unregistering master mount point", id);
- salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, new NetconfDeviceCapabilities());
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, NetconfDeviceCapabilities.empty());
unregisterMasterMountPoint();
}
private void registerMasterMountPoint() {
requireNonNull(id);
- requireNonNull(currentMountContext, "Device has no remote schema context yet. Probably not fully connected.");
- requireNonNull(netconfSessionPreferences, "Device has no capabilities yet. Probably not fully connected.");
+
+ final var mountContext = requireNonNull(currentSchema,
+ "Device has no remote schema context yet. Probably not fully connected.")
+ .mountContext();
+ final var preferences = requireNonNull(netconfSessionPreferences,
+ "Device has no capabilities yet. Probably not fully connected.");
final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
- deviceDataBroker = newDeviceDataBroker();
- netconfService = newNetconfDataTreeService();
+ deviceDataBroker = newDeviceDataBroker(mountContext, preferences);
+ netconfService = newNetconfDataTreeService(mountContext, preferences);
// We need to create ProxyDOMDataBroker so accessing mountpoint
// on leader node would be same as on follower node
actorResponseWaitTime);
final NetconfDataTreeService proxyNetconfService = new ProxyNetconfDataTreeService(id, masterActorRef,
actorSystem.dispatcher(), actorResponseWaitTime);
- salProvider.getMountInstance().onTopologyDeviceConnected(currentMountContext.getEffectiveModelContext(),
+ salProvider.getMountInstance().onTopologyDeviceConnected(mountContext.getEffectiveModelContext(),
proxyDataBroker, proxyNetconfService, deviceRpc, notificationService, deviceAction);
}
- protected DOMDataBroker newDeviceDataBroker() {
- return new NetconfDeviceDataBroker(id, currentMountContext, deviceRpc, netconfSessionPreferences);
+ protected DOMDataBroker newDeviceDataBroker(final MountPointContext mountContext,
+ final NetconfSessionPreferences preferences) {
+ return new NetconfDeviceDataBroker(id, mountContext, deviceRpc, preferences);
}
- protected NetconfDataTreeService newNetconfDataTreeService() {
- return AbstractNetconfDataTreeService.of(id, currentMountContext, deviceRpc, netconfSessionPreferences);
+ protected NetconfDataTreeService newNetconfDataTreeService(final MountPointContext mountContext,
+ final NetconfSessionPreferences preferences) {
+ return AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, preferences);
}
private Future<Object> sendInitialDataToActor() {
final List<SourceIdentifier> sourceIdentifiers = List.copyOf(SchemaContextUtil.getConstituentModuleIdentifiers(
- currentMountContext.getEffectiveModelContext()));
+ currentSchema.mountContext().getEffectiveModelContext()));
LOG.debug("{}: Sending CreateInitialMasterActorData with sourceIdentifiers {} to {}", id, sourceIdentifiers,
masterActorRef);
final String masterAddress = Cluster.get(actorSystem).selfAddress().toString();
LOG.debug("{}: updateDeviceData with master address {}", id, masterAddress);
salProvider.getTopologyDatastoreAdapter().updateClusteredDeviceData(true, masterAddress,
- netconfSessionPreferences.getNetconfDeviceCapabilities());
+ currentSchema.capabilities());
}
private void unregisterMasterMountPoint() {
import org.opendaylight.netconf.sal.connect.api.DeviceActionFactory;
import org.opendaylight.netconf.sal.connect.api.SchemaResourceManager;
import org.opendaylight.netconf.sal.connect.impl.DefaultSchemaResourceManager;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.topology.singleton.impl.utils.ClusteringRpcException;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.rfc8528.data.util.EmptyMountPointContext;
import org.opendaylight.yangtools.util.concurrent.FluentFutures;
import org.opendaylight.yangtools.yang.binding.DataObject;
final var spiedContext = spy(context);
doAnswer(invocation -> {
final var spiedFacade = (MasterSalFacade) spy(invocation.callRealMethod());
- doReturn(deviceDOMDataBroker).when(spiedFacade).newDeviceDataBroker();
+ doReturn(deviceDOMDataBroker).when(spiedFacade)
+ .newDeviceDataBroker(any(MountPointContext.class), any(NetconfSessionPreferences.class));
masterSalFacadeFuture.set(spiedFacade);
return spiedFacade;
}).when(spiedContext).newMasterSalFacade();
writeNetconfNode(TEST_DEFAULT_SUBDIR, masterDataBroker);
final var masterSalFacade = masterSalFacadeFuture.get(5, TimeUnit.SECONDS);
- masterSalFacade.onDeviceConnected(new EmptyMountPointContext(deviceSchemaContext),
- NetconfSessionPreferences.fromStrings(
- List.of(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString())),
- deviceRpcService.getRpcService());
+ masterSalFacade.onDeviceConnected(new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(),
+ new EmptyMountPointContext(deviceSchemaContext)),
+ NetconfSessionPreferences.fromStrings(
+ List.of(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString())),
+ deviceRpcService.getRpcService());
final var masterMountPoint = awaitMountPoint(masterMountPointService);
verify(masterMountPointListener, timeout(5000)).onMountPointRemoved(yangNodeInstanceId);
final var masterSalFacade = masterSalFacadeFuture.get(5, TimeUnit.SECONDS);
- masterSalFacade.onDeviceConnected(new EmptyMountPointContext(deviceSchemaContext),
- NetconfSessionPreferences.fromStrings(List.of(
+ masterSalFacade.onDeviceConnected(new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(),
+ new EmptyMountPointContext(deviceSchemaContext)), NetconfSessionPreferences.fromStrings(List.of(
NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString())),
deviceRpcService.getRpcService());
import org.opendaylight.mdsal.dom.api.DOMActionService;
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
public interface RemoteDeviceHandler extends AutoCloseable {
/**
* When device connected, init new mount point with specific schema context and DOM services.
*
- * @param remoteSchemaContext - schema context of connected device
+ * @param deviceSchema - {@link NetconfDeviceSchema} of connected device
* @param sessionPreferences - session of device
* @param deviceRpc - {@link DOMRpcService} of device
*/
- default void onDeviceConnected(final MountPointContext remoteSchemaContext,
+ default void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences sessionPreferences, final DOMRpcService deviceRpc) {
// DO NOTHING
}
/**
* When device connected, init new mount point with specific schema context and DOM services.
*
- * @param mountContext - MountPointContext of connected device
+ * @param deviceSchema - {@link NetconfDeviceSchema} of connected device
* @param sessionPreferences - session of device
* @param deviceRpc - {@link DOMRpcService} of device
* @param deviceAction - {@link DOMActionService} of device
*/
- default void onDeviceConnected(final MountPointContext mountContext,
+ default void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences sessionPreferences,
final DOMRpcService deviceRpc, final DOMActionService deviceAction) {
// DO NOTHING
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.checkerframework.checker.lock.qual.GuardedBy;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.notifications.rev120206.NetconfCapabilityChange;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapabilityBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability.FailureReason;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.rfc8528.data.util.EmptyMountPointContext;
}
// Set up the SchemaContext for the device
- final ListenableFuture<EffectiveModelContext> futureSchema = Futures.transformAsync(sourceResolverFuture,
+ final ListenableFuture<SchemaResult> futureSchema = Futures.transformAsync(sourceResolverFuture,
deviceSources -> assembleSchemaContext(deviceSources, remoteSessionCapabilities), processingExecutor);
// Potentially acquire mount point list and interpret it
- final ListenableFuture<MountPointContext> futureContext = Futures.transformAsync(futureSchema,
- schemaContext -> createMountPointContext(schemaContext, baseSchema, listener), processingExecutor);
+ final ListenableFuture<NetconfDeviceSchema> futureContext = Futures.transformAsync(futureSchema,
+ result -> Futures.transform(createMountPointContext(result.modelContext(), baseSchema, listener),
+ mount -> new NetconfDeviceSchema(result.capabilities(), mount), processingExecutor),
+ processingExecutor);
- Futures.addCallback(futureContext, new FutureCallback<MountPointContext>() {
+ Futures.addCallback(futureContext, new FutureCallback<>() {
@Override
- public void onSuccess(final MountPointContext result) {
+ public void onSuccess(final NetconfDeviceSchema result) {
handleSalInitializationSuccess(result, remoteSessionCapabilities,
- getDeviceSpecificRpc(result, listener, baseSchema), listener);
+ getDeviceSpecificRpc(result.mountContext(), listener, baseSchema), listener);
}
@Override
return remoteSessionCapabilities.isNotificationsSupported() && reconnectOnSchemasChange;
}
- private synchronized void handleSalInitializationSuccess(final MountPointContext result,
+ private synchronized void handleSalInitializationSuccess(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences remoteSessionCapabilities, final DOMRpcService deviceRpc,
final RemoteDeviceCommunicator listener) {
//NetconfDevice.SchemaSetup can complete after NetconfDeviceCommunicator was closed. In that case do nothing,
//since salFacade.onDeviceDisconnected was already called.
if (connected) {
- messageTransformer = new NetconfMessageTransformer(result, true,
+ final var mount = deviceSchema.mountContext();
+ messageTransformer = new NetconfMessageTransformer(mount, true,
resolveBaseSchema(remoteSessionCapabilities.isNotificationsSupported()));
// salFacade.onDeviceConnected has to be called before the notification handler is initialized
- salFacade.onDeviceConnected(result, remoteSessionCapabilities, deviceRpc,
+ salFacade.onDeviceConnected(deviceSchema, remoteSessionCapabilities, deviceRpc,
deviceActionFactory == null ? null : deviceActionFactory.createDeviceAction(
- messageTransformer, listener, result.getEffectiveModelContext()));
+ messageTransformer, listener, mount.getEffectiveModelContext()));
notificationHandler.onRemoteSchemaUp(messageTransformer);
LOG.info("{}: Netconf connector initialized successfully", id);
this.connected = connected;
}
- private ListenableFuture<EffectiveModelContext> assembleSchemaContext(final DeviceSources deviceSources,
+ private ListenableFuture<SchemaResult> assembleSchemaContext(final DeviceSources deviceSources,
final NetconfSessionPreferences remoteSessionCapabilities) {
LOG.debug("{}: Resolved device sources to {}", id, deviceSources);
return new SchemaSetup(deviceSources, remoteSessionCapabilities).startResolution();
}
- private ListenableFuture<MountPointContext> createMountPointContext(final EffectiveModelContext schemaContext,
- final BaseSchema baseSchema, final NetconfDeviceCommunicator listener) {
+ private ListenableFuture<@NonNull MountPointContext> createMountPointContext(
+ final EffectiveModelContext schemaContext, final BaseSchema baseSchema,
+ final NetconfDeviceCommunicator listener) {
final MountPointContext emptyContext = new EmptyMountPointContext(schemaContext);
if (schemaContext.findModule(SchemaMountConstants.RFC8528_MODULE).isEmpty()) {
return Futures.immediateFuture(emptyContext);
}
}
+ /**
+ * {@link NetconfDeviceCapabilities} and {@link EffectiveModelContext}.
+ */
+ private record SchemaResult(
+ @NonNull NetconfDeviceCapabilities capabilities,
+ @NonNull EffectiveModelContext modelContext) {
+
+ SchemaResult {
+ requireNonNull(capabilities);
+ requireNonNull(modelContext);
+ }
+ }
+
/**
* Schema builder that tries to build schema context from provided sources or biggest subset of it.
*/
private final class SchemaSetup implements FutureCallback<EffectiveModelContext> {
- private final SettableFuture<EffectiveModelContext> resultFuture = SettableFuture.create();
+ private final SettableFuture<SchemaResult> resultFuture = SettableFuture.create();
+
+ private final Set<AvailableCapability> nonModuleBasedCapabilities = new HashSet<>();
+ private final Map<QName, FailureReason> unresolvedCapabilites = new HashMap<>();
+ private final Set<AvailableCapability> resolvedCapabilities = new HashSet<>();
private final DeviceSources deviceSources;
private final NetconfSessionPreferences remoteSessionCapabilities;
- private final NetconfDeviceCapabilities capabilities;
private Collection<SourceIdentifier> requiredSources;
SchemaSetup(final DeviceSources deviceSources, final NetconfSessionPreferences remoteSessionCapabilities) {
this.deviceSources = deviceSources;
this.remoteSessionCapabilities = remoteSessionCapabilities;
- capabilities = remoteSessionCapabilities.getNetconfDeviceCapabilities();
// If device supports notifications and does not contain necessary modules, add them automatically
if (remoteSessionCapabilities.containsNonModuleCapability(
requiredSources = deviceSources.getRequiredSources();
final Collection<SourceIdentifier> missingSources = filterMissingSources(requiredSources);
- capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(missingSources),
- UnavailableCapability.FailureReason.MissingSource);
+ addUnresolvedCapabilities(getQNameFromSourceIdentifiers(missingSources),
+ UnavailableCapability.FailureReason.MissingSource);
requiredSources.removeAll(missingSources);
}
- ListenableFuture<EffectiveModelContext> startResolution() {
+ ListenableFuture<SchemaResult> startResolution() {
trySetupSchema();
return resultFuture;
}
LOG.debug("{}: Schema context built successfully from {}", id, requiredSources);
final Collection<QName> filteredQNames = Sets.difference(deviceSources.getRequiredSourcesQName(),
- capabilities.getUnresolvedCapabilites().keySet());
- capabilities.addCapabilities(filteredQNames.stream().map(entry -> new AvailableCapabilityBuilder()
- .setCapability(entry.toString()).setCapabilityOrigin(
- remoteSessionCapabilities.getModuleBasedCapsOrigin().get(entry)).build())
- .collect(Collectors.toList()));
-
- capabilities.addNonModuleBasedCapabilities(remoteSessionCapabilities
- .getNonModuleCaps().stream().map(entry -> new AvailableCapabilityBuilder()
- .setCapability(entry).setCapabilityOrigin(
- remoteSessionCapabilities.getNonModuleBasedCapsOrigin().get(entry)).build())
- .collect(Collectors.toList()));
-
- resultFuture.set(result);
+ unresolvedCapabilites.keySet());
+ resolvedCapabilities.addAll(filteredQNames.stream()
+ .map(capability -> new AvailableCapabilityBuilder()
+ .setCapability(capability.toString())
+ .setCapabilityOrigin(remoteSessionCapabilities.capabilityOrigin(capability))
+ .build())
+ .collect(Collectors.toList()));
+
+ nonModuleBasedCapabilities.addAll(remoteSessionCapabilities.getNonModuleCaps().stream()
+ .map(capability -> new AvailableCapabilityBuilder()
+ .setCapability(capability)
+ .setCapabilityOrigin(remoteSessionCapabilities.capabilityOrigin(capability))
+ .build())
+ .collect(Collectors.toList()));
+
+
+ resultFuture.set(new SchemaResult(new NetconfDeviceCapabilities(ImmutableMap.copyOf(unresolvedCapabilites),
+ ImmutableSet.copyOf(resolvedCapabilities), ImmutableSet.copyOf(nonModuleBasedCapabilities)), result));
}
@Override
}).collect(Collectors.toList());
}
+ private void addUnresolvedCapabilities(final Collection<QName> capabilities, final FailureReason reason) {
+ for (QName s : capabilities) {
+ unresolvedCapabilites.put(s, reason);
+ }
+ }
+
private List<SourceIdentifier> handleMissingSchemaSourceException(
final MissingSchemaSourceException exception) {
// In case source missing, try without it
id, missingSource);
LOG.debug("{}: Unable to build schema context, missing source {}, will reattempt without it",
id, missingSource, exception);
- final Collection<QName> qNameOfMissingSource =
- getQNameFromSourceIdentifiers(Sets.newHashSet(missingSource));
+ final var qNameOfMissingSource = getQNameFromSourceIdentifiers(Sets.newHashSet(missingSource));
if (!qNameOfMissingSource.isEmpty()) {
- capabilities.addUnresolvedCapabilities(
- qNameOfMissingSource, UnavailableCapability.FailureReason.MissingSource);
+ addUnresolvedCapabilities(qNameOfMissingSource, UnavailableCapability.FailureReason.MissingSource);
}
return stripUnavailableSource(missingSource);
}
id, failedSourceId);
LOG.warn("{}: Unable to build schema context, failed to resolve source {}, will reattempt without it",
id, failedSourceId, resolutionException);
- capabilities.addUnresolvedCapabilities(
- getQNameFromSourceIdentifiers(Collections.singleton(failedSourceId)),
+ addUnresolvedCapabilities(getQNameFromSourceIdentifiers(List.of(failedSourceId)),
UnavailableCapability.FailureReason.UnableToResolve);
return stripUnavailableSource(resolutionException.getFailedSource());
}
// unsatisfied imports
- final Set<SourceIdentifier> unresolvedSources = resolutionException.getUnsatisfiedImports().keySet();
- capabilities.addUnresolvedCapabilities(getQNameFromSourceIdentifiers(unresolvedSources),
+ addUnresolvedCapabilities(
+ getQNameFromSourceIdentifiers(resolutionException.getUnsatisfiedImports().keySet()),
UnavailableCapability.FailureReason.UnableToResolve);
LOG.warn("{}: Unable to build schema context, unsatisfied imports {}, will reattempt with resolved only",
id, resolutionException.getUnsatisfiedImports());
--- /dev/null
+/*
+ * Copyright (c) 2022 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.sal.connect.netconf;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
+import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+/**
+ * {@link NetconfDeviceCapabilities} and {@link EffectiveModelContext} pertaining to a {@link NetconfDevice}.
+ */
+public record NetconfDeviceSchema(
+ @NonNull NetconfDeviceCapabilities capabilities,
+ @NonNull MountPointContext mountContext) {
+
+ public NetconfDeviceSchema {
+ requireNonNull(capabilities);
+ requireNonNull(mountContext);
+ }
+}
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.sal.SchemalessNetconfDeviceRpc;
final SchemalessNetconfDeviceRpc schemalessNetconfDeviceRpc = new SchemalessNetconfDeviceRpc(id,
netconfDeviceCommunicator, rpcTransformer, messageTransformer);
- salFacade.onDeviceConnected(baseSchemas.getBaseSchema().getMountPointContext(),
- remoteSessionCapabilities, schemalessNetconfDeviceRpc);
+ salFacade.onDeviceConnected(
+ // FIXME: or bound from base schema rather?
+ new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(),
+ baseSchemas.getBaseSchema().getMountPointContext()),
+ remoteSessionCapabilities, schemalessNetconfDeviceRpc);
}
@Override
* 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.sal.connect.netconf.listener;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.unavailable.capabilities.UnavailableCapability.FailureReason;
import org.opendaylight.yangtools.yang.common.QName;
-public final class NetconfDeviceCapabilities {
- private final Map<QName, FailureReason> unresolvedCapabilites;
- private final Set<AvailableCapability> resolvedCapabilities;
- private final Set<AvailableCapability> nonModuleBasedCapabilities;
-
- public NetconfDeviceCapabilities() {
- this.unresolvedCapabilites = new HashMap<>();
- this.resolvedCapabilities = new HashSet<>();
- this.nonModuleBasedCapabilities = new HashSet<>();
- }
-
- public void addUnresolvedCapability(QName source, FailureReason reason) {
- unresolvedCapabilites.put(source, reason);
- }
-
- public void addUnresolvedCapabilities(Collection<QName> capabilities, FailureReason reason) {
- for (QName s : capabilities) {
- unresolvedCapabilites.put(s, reason);
- }
- }
+public record NetconfDeviceCapabilities(
+ @NonNull ImmutableMap<QName, FailureReason> unresolvedCapabilites,
+ @NonNull ImmutableSet<AvailableCapability> resolvedCapabilities,
+ @NonNull ImmutableSet<AvailableCapability> nonModuleBasedCapabilities) {
+ private static final @NonNull NetconfDeviceCapabilities EMPTY =
+ new NetconfDeviceCapabilities(ImmutableMap.of(), ImmutableSet.of(), ImmutableSet.of());
- public void addCapabilities(Collection<AvailableCapability> availableSchemas) {
- resolvedCapabilities.addAll(availableSchemas);
+ public NetconfDeviceCapabilities {
+ requireNonNull(unresolvedCapabilites);
+ requireNonNull(resolvedCapabilities);
+ requireNonNull(nonModuleBasedCapabilities);
}
- public void addNonModuleBasedCapabilities(Collection<AvailableCapability> nonModuleCapabilities) {
- this.nonModuleBasedCapabilities.addAll(nonModuleCapabilities);
+ public static @NonNull NetconfDeviceCapabilities empty() {
+ return EMPTY;
}
-
- public Set<AvailableCapability> getNonModuleBasedCapabilities() {
- return nonModuleBasedCapabilities;
- }
-
- public Map<QName, FailureReason> getUnresolvedCapabilites() {
- return unresolvedCapabilites;
- }
-
- public Set<AvailableCapability> getResolvedCapabilities() {
- return resolvedCapabilities;
- }
-
}
LOG.debug("{}: Session established", id);
currentSession = session;
- NetconfSessionPreferences netconfSessionPreferences =
- NetconfSessionPreferences.fromNetconfSession(session);
- LOG.trace("{}: Session advertised capabilities: {}", id,
- netconfSessionPreferences);
+ var netconfSessionPreferences = NetconfSessionPreferences.fromNetconfSession(session);
+ LOG.trace("{}: Session advertised capabilities: {}", id, netconfSessionPreferences);
final var localOverride = overrideNetconfCapabilities;
if (localOverride != null) {
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.netconf.client.NetconfClientSession;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin;
private static final Splitter AMP_SPLITTER = Splitter.on('&');
private static final Predicate<String> CONTAINS_REVISION = input -> input.contains("revision=");
- private final NetconfDeviceCapabilities capabilities = new NetconfDeviceCapabilities();
private final ImmutableMap<QName, CapabilityOrigin> moduleBasedCaps;
private final ImmutableMap<String, CapabilityOrigin> nonModuleCaps;
return nonModuleCaps;
}
- public NetconfDeviceCapabilities getNetconfDeviceCapabilities() {
- return capabilities;
+ public @Nullable CapabilityOrigin capabilityOrigin(final QName capability) {
+ return moduleBasedCaps.get(requireNonNull(capability));
+ }
+
+ public @Nullable CapabilityOrigin capabilityOrigin(final String capability) {
+ return nonModuleCaps.get(requireNonNull(capability));
}
// allows partial matches - assuming parameters are in the same order
import org.opendaylight.mdsal.dom.api.DOMRpcResult;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
}
@Override
- public void onDeviceConnected(final MountPointContext remoteSchemaContext,
- final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
- onDeviceConnected(remoteSchemaContext, netconfSessionPreferences, deviceRpc, null);
+ public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
+ final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc) {
+ onDeviceConnected(deviceSchema, netconfSessionPreferences, deviceRpc, null);
}
@Override
- public void onDeviceConnected(final MountPointContext remoteSchemaContext,
+ public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService deviceRpc,
final DOMActionService deviceAction) {
currentDeviceRpc = requireNonNull(deviceRpc);
- salFacade.onDeviceConnected(remoteSchemaContext, netconfSessionPreferences,
+ salFacade.onDeviceConnected(deviceSchema, netconfSessionPreferences,
new KeepaliveDOMRpcService(deviceRpc), deviceAction);
LOG.debug("{}: Netconf session initiated, starting keepalives", id);
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
}
@Override
- public synchronized void onDeviceConnected(final MountPointContext mountContext,
- final NetconfSessionPreferences netconfSessionPreferences,
- final DOMRpcService deviceRpc, final DOMActionService deviceAction) {
+ public synchronized void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
+ final NetconfSessionPreferences sessionPreferences, final DOMRpcService deviceRpc,
+ final DOMActionService deviceAction) {
+ final MountPointContext mountContext = deviceSchema.mountContext();
final EffectiveModelContext schemaContext = mountContext.getEffectiveModelContext();
+
final NetconfDeviceDataBroker netconfDeviceDataBroker =
- new NetconfDeviceDataBroker(id, mountContext, deviceRpc, netconfSessionPreferences);
+ new NetconfDeviceDataBroker(id, mountContext, deviceRpc, sessionPreferences);
final NetconfDataTreeService netconfService =
- AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, netconfSessionPreferences);
+ AbstractNetconfDataTreeService.of(id, mountContext, deviceRpc, sessionPreferences);
registerLockListener(netconfDeviceDataBroker, netconfService);
final NetconfDeviceNotificationService notificationService = new NetconfDeviceNotificationService();
- salProvider.getMountInstance()
- .onTopologyDeviceConnected(schemaContext, netconfDeviceDataBroker, netconfService,
- deviceRpc, notificationService, deviceAction);
- salProvider.getTopologyDatastoreAdapter()
- .updateDeviceData(true, netconfSessionPreferences.getNetconfDeviceCapabilities());
+ salProvider.getMountInstance().onTopologyDeviceConnected(schemaContext, netconfDeviceDataBroker, netconfService,
+ deviceRpc, notificationService, deviceAction);
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(true, deviceSchema.capabilities());
}
@Override
public synchronized void onDeviceDisconnected() {
- salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, new NetconfDeviceCapabilities());
+ salProvider.getTopologyDatastoreAdapter().updateDeviceData(false, NetconfDeviceCapabilities.empty());
salProvider.getMountInstance().onTopologyDeviceDisconnected();
closeLockChangeListener();
}
.setConnectionStatus(up ? ConnectionStatus.Connected : ConnectionStatus.Connecting)
.setAvailableCapabilities(new AvailableCapabilitiesBuilder()
.setAvailableCapability(ImmutableList.<AvailableCapability>builder()
- .addAll(capabilities.getNonModuleBasedCapabilities())
- .addAll(capabilities.getResolvedCapabilities())
+ .addAll(capabilities.nonModuleBasedCapabilities())
+ .addAll(capabilities.resolvedCapabilities())
.build())
.build())
.setUnavailableCapabilities(new UnavailableCapabilitiesBuilder()
- .setUnavailableCapability(capabilities.getUnresolvedCapabilites().entrySet().stream()
+ .setUnavailableCapability(capabilities.unresolvedCapabilites().entrySet().stream()
.map(unresolved -> new UnavailableCapabilityBuilder()
// FIXME: better conversion than 'toString' ?
.setCapability(unresolved.getKey().toString())
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
device.onRemoteSessionUp(sessionCaps, listener);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class),
+ verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class), isNull());
verify(schemaFactory, times(2)).createEffectiveModelContext(anyCollection());
}
getSessionCaps(true, Lists.newArrayList(TEST_CAPABILITY, TEST_CAPABILITY2));
device.onRemoteSessionUp(sessionCaps, listener);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class),
+ verify(facade, timeout(5000)).onDeviceConnected(any(NetconfDeviceSchema.class),
any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class), isNull());
verify(schemaFactory, times(1)).createEffectiveModelContext(anyCollection());
}
verify(schemaContextProviderFactory, timeout(5000)).createEffectiveModelContext(any(Collection.class));
verify(facade, timeout(5000)).onDeviceConnected(
- any(MountPointContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
+ any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
isNull());
device.onRemoteSessionDown();
verify(schemaContextProviderFactory, timeout(5000).times(2)).createEffectiveModelContext(any(Collection.class));
verify(facade, timeout(5000).times(2)).onDeviceConnected(
- any(MountPointContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
+ any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class),
isNull());
}
netconfSpy.onRemoteSessionUp(sessionCaps.replaceModuleCaps(moduleBasedCaps), listener);
- final ArgumentCaptor<NetconfSessionPreferences> argument =
- ArgumentCaptor.forClass(NetconfSessionPreferences.class);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class), argument.capture(),
+ final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
+ verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
any(DOMRpcService.class), isNull());
- final NetconfDeviceCapabilities netconfDeviceCaps = argument.getValue().getNetconfDeviceCapabilities();
-
- netconfDeviceCaps.getResolvedCapabilities()
+ argument.getValue().capabilities().resolvedCapabilities()
.forEach(entry -> assertEquals("Builded 'AvailableCapability' schemas should match input capabilities.",
moduleBasedCaps.get(
QName.create(entry.getCapability())).getName(), entry.getCapabilityOrigin().getName()));
netconfSpy.onRemoteSessionUp(sessionCaps, listener);
- final ArgumentCaptor<NetconfSessionPreferences> argument =
- ArgumentCaptor.forClass(NetconfSessionPreferences.class);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class), argument.capture(),
+ final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
+ verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
any(DOMRpcService.class), isNull());
List<String> notificationModulesName = Arrays.asList(
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
.$YangModuleInfoImpl.getInstance().getName().toString());
- final Set<AvailableCapability> resolvedCapabilities = argument.getValue().getNetconfDeviceCapabilities()
- .getResolvedCapabilities();
+ final Set<AvailableCapability> resolvedCapabilities = argument.getValue().capabilities().resolvedCapabilities();
assertEquals(2, resolvedCapabilities.size());
assertTrue(resolvedCapabilities.stream().anyMatch(entry -> notificationModulesName
netconfSpy.onRemoteSessionUp(sessionCaps, listener);
- final ArgumentCaptor<NetconfSessionPreferences> argument =
- ArgumentCaptor.forClass(NetconfSessionPreferences.class);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class), argument.capture(),
+ final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
+ verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
any(DOMRpcService.class), isNull());
- final NetconfDeviceCapabilities netconfDeviceCaps = argument.getValue().getNetconfDeviceCapabilities();
+ final NetconfDeviceCapabilities netconfDeviceCaps = argument.getValue().capabilities();
- List<String> notificationModulesName = Arrays.asList(
+ List<String> notificationModulesName = List.of(
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
.$YangModuleInfoImpl.getInstance().getName().toString(),
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715
.$YangModuleInfoImpl.getInstance().getName().toString());
- assertFalse(netconfDeviceCaps.getResolvedCapabilities().stream().anyMatch(entry -> notificationModulesName
- .contains(entry.getCapability())));
+ assertFalse(netconfDeviceCaps.resolvedCapabilities().stream()
+ .anyMatch(entry -> notificationModulesName.contains(entry.getCapability())));
}
@Test
netconfSpy.onRemoteSessionUp(sessionCaps.replaceModuleCaps(moduleBasedCaps), listener);
- final ArgumentCaptor<NetconfSessionPreferences> argument =
- ArgumentCaptor.forClass(NetconfSessionPreferences.class);
- verify(facade, timeout(5000)).onDeviceConnected(any(MountPointContext.class), argument.capture(),
+ final ArgumentCaptor<NetconfDeviceSchema> argument = ArgumentCaptor.forClass(NetconfDeviceSchema.class);
+ verify(facade, timeout(5000)).onDeviceConnected(argument.capture(), any(NetconfSessionPreferences.class),
any(DOMRpcService.class), isNull());
- final Set<AvailableCapability> resolvedCapabilities = argument.getValue().getNetconfDeviceCapabilities()
- .getResolvedCapabilities();
+ final Set<AvailableCapability> resolvedCapabilities = argument.getValue().capabilities().resolvedCapabilities();
List<String> notificationModulesName = Arrays.asList(
org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714
private static RemoteDeviceHandler getFacade() throws Exception {
final RemoteDeviceHandler remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
doNothing().when(remoteDeviceHandler).onDeviceConnected(
- any(MountPointContext.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class),
+ any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class),
any(DOMActionService.class));
doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
import org.opendaylight.netconf.sal.connect.netconf.schema.mapping.SchemalessMessageTransformer;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
public class SchemalessNetconfDeviceTest extends AbstractBaseSchemasTest {
device.onRemoteSessionUp(sessionCaps, listener);
verify(facade).onDeviceConnected(
- any(MountPointContext.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
+ any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(DOMRpcService.class));
device.onNotification(netconfMessage);
verify(facade).onNotification(isNull());
private static RemoteDeviceHandler getFacade() throws Exception {
final RemoteDeviceHandler remoteDeviceHandler = mockCloseableClass(RemoteDeviceHandler.class);
doNothing().when(remoteDeviceHandler).onDeviceConnected(
- any(MountPointContext.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
+ any(NetconfDeviceSchema.class), any(NetconfSessionPreferences.class), any(NetconfDeviceRpc.class));
doNothing().when(remoteDeviceHandler).onDeviceDisconnected();
doNothing().when(remoteDeviceHandler).onNotification(any(DOMNotification.class));
return remoteDeviceHandler;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.google.common.collect.Lists;
import java.util.List;
import org.junit.Test;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
-import org.opendaylight.yangtools.yang.common.QName;
public class NetconfSessionPreferencesTest {
-
@Test
- public void testMerge() throws Exception {
- final List<String> caps1 = Lists.newArrayList(
- "namespace:1?module=module1&revision=2012-12-12",
- "namespace:2?module=module2&revision=2012-12-12",
- "urn:ietf:params:xml:ns:yang:"
- + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
- "urn:ietf:params:netconf:base:1.0",
- "urn:ietf:params:netconf:capability:rollback-on-error:1.0"
- );
- final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ public void testMerge() {
+ final var sessionCaps1 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring"
+ + "&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
assertCaps(sessionCaps1, 2, 3);
- final List<String> caps2 = Lists.newArrayList(
- "namespace:3?module=module3&revision=2012-12-12",
- "namespace:4?module=module4&revision=2012-12-12",
- "randomNonModuleCap"
- );
- final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ final var sessionCaps2 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "randomNonModuleCap"));
assertCaps(sessionCaps2, 1, 2);
- final NetconfSessionPreferences merged = sessionCaps1.addModuleCaps(sessionCaps2);
+ final var merged = sessionCaps1.addModuleCaps(sessionCaps2);
assertCaps(merged, 2, 2 + 1 /*Preserved monitoring*/ + 2 /*already present*/);
- for (final QName qualifiedName : sessionCaps2.getModuleBasedCaps()) {
- assertThat(merged.getModuleBasedCaps(), hasItem(qualifiedName));
+ for (var qname : sessionCaps2.getModuleBasedCaps()) {
+ assertThat(merged.getModuleBasedCaps(), hasItem(qname));
}
assertThat(merged.getModuleBasedCaps(), hasItem(NetconfMessageTransformUtil.IETF_NETCONF_MONITORING));
@Test
public void testReplace() throws Exception {
- final List<String> caps1 = Lists.newArrayList(
- "namespace:1?module=module1&revision=2012-12-12",
- "namespace:2?module=module2&revision=2012-12-12",
- "urn:ietf:params:xml:ns:yang:"
- + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
- "urn:ietf:params:netconf:base:1.0",
- "urn:ietf:params:netconf:capability:rollback-on-error:1.0"
- );
- final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ final var sessionCaps1 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:"
+ + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
assertCaps(sessionCaps1, 2, 3);
- final List<String> caps2 = Lists.newArrayList(
- "namespace:3?module=module3&revision=2012-12-12",
- "namespace:4?module=module4&revision=2012-12-12",
- "randomNonModuleCap"
- );
- final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ final var sessionCaps2 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "randomNonModuleCap"));
assertCaps(sessionCaps2, 1, 2);
-
- final NetconfSessionPreferences replaced = sessionCaps1.replaceModuleCaps(sessionCaps2);
- assertCaps(replaced, 2, 2);
+ assertCaps(sessionCaps1.replaceModuleCaps(sessionCaps2), 2, 2);
}
@Test
public void testNonModuleMerge() throws Exception {
- final List<String> caps1 = Lists.newArrayList(
- "namespace:1?module=module1&revision=2012-12-12",
- "namespace:2?module=module2&revision=2012-12-12",
- "urn:ietf:params:xml:ns:yang:"
- + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
- "urn:ietf:params:netconf:base:1.0",
- "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
- "urn:ietf:params:netconf:capability:candidate:1.0"
- );
- final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ final var sessionCaps1 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:"
+ + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
+ "urn:ietf:params:netconf:capability:candidate:1.0"));
assertCaps(sessionCaps1, 3, 3);
assertTrue(sessionCaps1.isCandidateSupported());
- final List<String> caps2 = Lists.newArrayList(
- "namespace:3?module=module3&revision=2012-12-12",
- "namespace:4?module=module4&revision=2012-12-12",
- "urn:ietf:params:netconf:capability:writable-running:1.0",
- "urn:ietf:params:netconf:capability:notification:1.0"
- );
- final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ final var sessionCaps2 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "urn:ietf:params:netconf:capability:writable-running:1.0",
+ "urn:ietf:params:netconf:capability:notification:1.0"));
assertCaps(sessionCaps2, 2, 2);
assertTrue(sessionCaps2.isRunningWritable());
- final NetconfSessionPreferences merged = sessionCaps1.addNonModuleCaps(sessionCaps2);
+ final var merged = sessionCaps1.addNonModuleCaps(sessionCaps2);
assertCaps(merged, 3 + 2, 3);
- for (final String capability : sessionCaps2.getNonModuleCaps()) {
- assertThat(merged.getNonModuleCaps(), hasItem(capability));
- }
+ sessionCaps2.getNonModuleCaps().forEach(
+ capability -> assertThat(merged.getNonModuleCaps(), hasItem(capability)));
assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:base:1.0"));
assertThat(merged.getNonModuleCaps(), hasItem("urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
@Test
public void testNonmoduleReplace() throws Exception {
- final List<String> caps1 = Lists.newArrayList(
- "namespace:1?module=module1&revision=2012-12-12",
- "namespace:2?module=module2&revision=2012-12-12",
- "urn:ietf:params:xml:ns:yang:"
- + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
- "urn:ietf:params:netconf:base:1.0",
- "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
- "urn:ietf:params:netconf:capability:candidate:1.0"
- );
- final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
+ final var sessionCaps1 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:1?module=module1&revision=2012-12-12",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "urn:ietf:params:xml:ns:yang:"
+ + "ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04",
+ "urn:ietf:params:netconf:base:1.0",
+ "urn:ietf:params:netconf:capability:rollback-on-error:1.0",
+ "urn:ietf:params:netconf:capability:candidate:1.0"));
assertCaps(sessionCaps1, 3, 3);
assertTrue(sessionCaps1.isCandidateSupported());
- final List<String> caps2 = Lists.newArrayList(
- "namespace:3?module=module3&revision=2012-12-12",
- "namespace:4?module=module4&revision=2012-12-12",
- "randomNonModuleCap",
- "urn:ietf:params:netconf:capability:writable-running:1.0"
- );
- final NetconfSessionPreferences sessionCaps2 = NetconfSessionPreferences.fromStrings(caps2);
+ final var sessionCaps2 = NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:3?module=module3&revision=2012-12-12",
+ "namespace:4?module=module4&revision=2012-12-12",
+ "randomNonModuleCap",
+ "urn:ietf:params:netconf:capability:writable-running:1.0"));
assertCaps(sessionCaps2, 2, 2);
assertTrue(sessionCaps2.isRunningWritable());
- final NetconfSessionPreferences replaced = sessionCaps1.replaceNonModuleCaps(sessionCaps2);
+ final var replaced = sessionCaps1.replaceNonModuleCaps(sessionCaps2);
assertCaps(replaced, 2, 3);
assertFalse(replaced.isCandidateSupported());
assertTrue(replaced.isRunningWritable());
@Test
public void testCapabilityNoRevision() throws Exception {
- final List<String> caps1 = Lists.newArrayList(
- "namespace:2?module=module2",
- "namespace:2?module=module2&revision=2012-12-12",
- "namespace:2?module=module1&RANDOMSTRING;revision=2013-12-12",
- // Revision parameter present, but no revision defined
- "namespace:2?module=module4&RANDOMSTRING;revision=",
- // This one should be ignored(same as first), since revision is in wrong format
- "namespace:2?module=module2&RANDOMSTRING;revision=2013-12-12"
- );
-
- final NetconfSessionPreferences sessionCaps1 = NetconfSessionPreferences.fromStrings(caps1);
- assertCaps(sessionCaps1, 0, 4);
+ assertCaps(NetconfSessionPreferences.fromStrings(List.of(
+ "namespace:2?module=module2",
+ "namespace:2?module=module2&revision=2012-12-12",
+ "namespace:2?module=module1&RANDOMSTRING;revision=2013-12-12",
+ // Revision parameter present, but no revision defined
+ "namespace:2?module=module4&RANDOMSTRING;revision=",
+ // This one should be ignored(same as first), since revision is in wrong format
+ "namespace:2?module=module2&RANDOMSTRING;revision=2013-12-12")),
+ 0, 4);
}
private static void assertCaps(final NetconfSessionPreferences sessionCaps1, final int nonModuleCaps,
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.netconf.sal.connect.api.RemoteDeviceHandler;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCommunicator;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.yangtools.rfc8528.data.api.MountPointContext;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
private DOMRpcService localDeviceRpc;
@Override
- public void onDeviceConnected(final MountPointContext remoteSchemaContext,
+ public void onDeviceConnected(final NetconfDeviceSchema deviceSchema,
final NetconfSessionPreferences netconfSessionPreferences, final DOMRpcService currentDeviceRpc,
final DOMActionService deviceAction) {
localDeviceRpc = currentDeviceRpc;
wtx.put(LogicalDatastoreType.OPERATIONAL, pathToAugmentedLeaf, augmentNode);
wtx.commit().get(5, TimeUnit.SECONDS);
- adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
+ adapter.updateDeviceData(true, NetconfDeviceCapabilities.empty());
assertEquals(Optional.of(dataTestId), domDataBroker.newReadOnlyTransaction()
.read(LogicalDatastoreType.OPERATIONAL, pathToAugmentedLeaf)
import org.opendaylight.mdsal.dom.api.DOMNotification;
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
+import org.opendaylight.netconf.sal.connect.netconf.NetconfDeviceSchema;
+import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfDeviceCapabilities;
import org.opendaylight.netconf.sal.connect.netconf.listener.NetconfSessionPreferences;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
List.of(NetconfMessageTransformUtil.NETCONF_CANDIDATE_URI.toString()));
final DOMRpcService deviceRpc = mock(DOMRpcService.class);
- deviceFacade.onDeviceConnected(new EmptyMountPointContext(schemaContext), netconfSessionPreferences, deviceRpc,
- null);
+ deviceFacade.onDeviceConnected(
+ new NetconfDeviceSchema(NetconfDeviceCapabilities.empty(), new EmptyMountPointContext(schemaContext)),
+ netconfSessionPreferences, deviceRpc, null);
+
verifyConnectionStatusUpdate(ConnectionStatus.Connected);
verify(mountInstance, times(1)).onTopologyDeviceConnected(eq(schemaContext),
any(DOMDataBroker.class), any(NetconfDataTreeService.class), eq(deviceRpc),
@Test
public void testDeviceUpdate() throws Exception {
- adapter.updateDeviceData(true, new NetconfDeviceCapabilities());
+ adapter.updateDeviceData(true, NetconfDeviceCapabilities.empty());
verify(mockChain, times(2)).newWriteOnlyTransaction();
verify(mockTx, times(1)).put(any(LogicalDatastoreType.class), any(InstanceIdentifier.class), any(Node.class));