X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=netconf%2Fsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fsal%2Fconnect%2Fnetconf%2Flistener%2FNetconfSessionPreferences.java;h=1a0911287d03b5a900d92bc5a5e2ea06dd6ca0b1;hb=3417b343bd99a20f4215b7d4f6041880e8667617;hp=ba03a603ee70a111ceb745494fa18e496d962f87;hpb=4f8fe6ca68115fecdb9ce43573af5a2e26c50b50;p=netconf.git diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/listener/NetconfSessionPreferences.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/listener/NetconfSessionPreferences.java index ba03a603ee..1a0911287d 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/listener/NetconfSessionPreferences.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/listener/NetconfSessionPreferences.java @@ -10,7 +10,6 @@ package org.opendaylight.netconf.sal.connect.netconf.listener; import static java.util.Objects.requireNonNull; import com.google.common.base.MoreObjects; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Splitter; import com.google.common.base.Strings; @@ -20,7 +19,8 @@ import com.google.common.collect.Maps; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; +import org.eclipse.jdt.annotation.NonNull; +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; @@ -29,63 +29,93 @@ import org.opendaylight.yangtools.yang.common.XMLNamespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public final class NetconfSessionPreferences { - - private static final class ParameterMatcher { - private final Predicate predicate; - private final int skipLength; - - ParameterMatcher(final String name) { - predicate = input -> input.startsWith(name); - - this.skipLength = name.length(); - } - - String from(final Iterable params) { - final Optional o = Iterables.tryFind(params, predicate); - if (!o.isPresent()) { - return null; - } - - return o.get().substring(skipLength); - } - } - +// FIXME: propagate to API with immutable semantics +public record NetconfSessionPreferences( + @NonNull ImmutableMap nonModuleCaps, + @NonNull ImmutableMap moduleBasedCaps) { private static final Logger LOG = LoggerFactory.getLogger(NetconfSessionPreferences.class); private static final ParameterMatcher MODULE_PARAM = new ParameterMatcher("module="); private static final ParameterMatcher REVISION_PARAM = new ParameterMatcher("revision="); private static final ParameterMatcher BROKEN_REVISON_PARAM = new ParameterMatcher("amp;revision="); private static final Splitter AMP_SPLITTER = Splitter.on('&'); - private static final Predicate CONTAINS_REVISION = input -> input.contains("revision="); - private final Map moduleBasedCaps; - private final Map nonModuleCaps; + public NetconfSessionPreferences { + requireNonNull(nonModuleCaps); + requireNonNull(moduleBasedCaps); + } - NetconfSessionPreferences(final Map nonModuleCaps, - final Map moduleBasedCaps) { - this.nonModuleCaps = requireNonNull(nonModuleCaps); - this.moduleBasedCaps = requireNonNull(moduleBasedCaps); + public static @NonNull NetconfSessionPreferences fromNetconfSession(final NetconfClientSession session) { + return fromStrings(session.getServerCapabilities()); } - public Set getModuleBasedCaps() { - return moduleBasedCaps.keySet(); + public static @NonNull NetconfSessionPreferences fromStrings(final Collection capabilities) { + // we do not know origin of capabilities from only Strings, so we set it to default value + return fromStrings(capabilities, CapabilityOrigin.DeviceAdvertised); } - public Map getModuleBasedCapsOrigin() { - return moduleBasedCaps; + public static @NonNull NetconfSessionPreferences fromStrings(final Collection capabilities, + final CapabilityOrigin capabilityOrigin) { + final var moduleBasedCaps = new HashMap(); + final var nonModuleCaps = new HashMap(); + + for (final String capability : capabilities) { + nonModuleCaps.put(capability, capabilityOrigin); + final int qmark = capability.indexOf('?'); + if (qmark == -1) { + continue; + } + + final String namespace = capability.substring(0, qmark); + final Iterable queryParams = AMP_SPLITTER.split(capability.substring(qmark + 1)); + final String moduleName = MODULE_PARAM.from(queryParams); + if (Strings.isNullOrEmpty(moduleName)) { + continue; + } + + String revision = REVISION_PARAM.from(queryParams); + if (!Strings.isNullOrEmpty(revision)) { + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName), + capabilityOrigin); + continue; + } + + /* + * We have seen devices which mis-escape revision, but the revision may not + * even be there. First check if there is a substring that matches revision. + */ + if (Iterables.any(queryParams, input -> input.contains("revision="))) { + LOG.debug("Netconf device was not reporting revision correctly, trying to get amp;revision="); + revision = BROKEN_REVISON_PARAM.from(queryParams); + if (Strings.isNullOrEmpty(revision)) { + LOG.warn("Netconf device returned revision incorrectly escaped for {}, ignoring it", capability); + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, + cachedQName(namespace, moduleName), capabilityOrigin); + } else { + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, + cachedQName(namespace, revision, moduleName), capabilityOrigin); + } + continue; + } + + // Fallback, no revision provided for module + addModuleQName(moduleBasedCaps, nonModuleCaps, capability, + cachedQName(namespace, moduleName), capabilityOrigin); + } + + return new NetconfSessionPreferences(ImmutableMap.copyOf(nonModuleCaps), ImmutableMap.copyOf(moduleBasedCaps)); } - public Set getNonModuleCaps() { - return nonModuleCaps.keySet(); + public @Nullable CapabilityOrigin capabilityOrigin(final QName capability) { + return moduleBasedCaps.get(requireNonNull(capability)); } - public Map getNonModuleBasedCapsOrigin() { - return nonModuleCaps; + public @Nullable CapabilityOrigin capabilityOrigin(final String capability) { + return nonModuleCaps.get(requireNonNull(capability)); } // allows partial matches - assuming parameters are in the same order public boolean containsPartialNonModuleCapability(final String capability) { - for (final String nonModuleCap : getNonModuleCaps()) { + for (var nonModuleCap : nonModuleCaps.keySet()) { if (nonModuleCap.startsWith(capability)) { LOG.trace("capability {} partially matches {}", capability, nonModuleCaps); return true; @@ -105,13 +135,13 @@ public final class NetconfSessionPreferences { @Override public String toString() { return MoreObjects.toStringHelper(this) - .add("capabilities", nonModuleCaps) - .add("moduleBasedCapabilities", moduleBasedCaps) - .add("rollback", isRollbackSupported()) - .add("monitoring", isMonitoringSupported()) - .add("candidate", isCandidateSupported()) - .add("writableRunning", isRunningWritable()) - .toString(); + .add("capabilities", nonModuleCaps) + .add("moduleBasedCapabilities", moduleBasedCaps) + .add("rollback", isRollbackSupported()) + .add("monitoring", isMonitoringSupported()) + .add("candidate", isCandidateSupported()) + .add("writableRunning", isRunningWritable()) + .toString(); } public boolean isRollbackSupported() { @@ -141,64 +171,53 @@ public final class NetconfSessionPreferences { * Merge module-based list of capabilities with current list of module-based capabilities. * * @param netconfSessionModuleCapabilities capabilities to merge into this - * * @return new instance of preferences with merged module-based capabilities */ public NetconfSessionPreferences addModuleCaps(final NetconfSessionPreferences netconfSessionModuleCapabilities) { - final Map mergedCaps = Maps.newHashMapWithExpectedSize(moduleBasedCaps.size() - + netconfSessionModuleCapabilities.getModuleBasedCaps().size()); + final var mergedCaps = Maps.newHashMapWithExpectedSize(moduleBasedCaps.size() + + netconfSessionModuleCapabilities.moduleBasedCaps.size()); mergedCaps.putAll(moduleBasedCaps); - mergedCaps.putAll(netconfSessionModuleCapabilities.getModuleBasedCapsOrigin()); - return new NetconfSessionPreferences(getNonModuleBasedCapsOrigin(), mergedCaps); + mergedCaps.putAll(netconfSessionModuleCapabilities.moduleBasedCaps); + return new NetconfSessionPreferences(nonModuleCaps, ImmutableMap.copyOf(mergedCaps)); } /** * Override current list of module-based capabilities. * * @param netconfSessionPreferences capabilities to override in this - * * @return new instance of preferences with replaced module-based capabilities */ public NetconfSessionPreferences replaceModuleCaps(final NetconfSessionPreferences netconfSessionPreferences) { - return new NetconfSessionPreferences( - getNonModuleBasedCapsOrigin(), netconfSessionPreferences.getModuleBasedCapsOrigin()); + return new NetconfSessionPreferences(nonModuleCaps, netconfSessionPreferences.moduleBasedCaps); } public NetconfSessionPreferences replaceModuleCaps(final Map newModuleBasedCaps) { - return new NetconfSessionPreferences(getNonModuleBasedCapsOrigin(), newModuleBasedCaps); + return new NetconfSessionPreferences(nonModuleCaps, ImmutableMap.copyOf(newModuleBasedCaps)); } - /** * Merge list of non-module based capabilities with current list of non-module based capabilities. * * @param netconfSessionNonModuleCapabilities capabilities to merge into this - * * @return new instance of preferences with merged non-module based capabilities */ public NetconfSessionPreferences addNonModuleCaps( final NetconfSessionPreferences netconfSessionNonModuleCapabilities) { - final Map mergedCaps = Maps.newHashMapWithExpectedSize( - nonModuleCaps.size() + netconfSessionNonModuleCapabilities.getNonModuleCaps().size()); - mergedCaps.putAll(getNonModuleBasedCapsOrigin()); - mergedCaps.putAll(netconfSessionNonModuleCapabilities.getNonModuleBasedCapsOrigin()); - return new NetconfSessionPreferences(mergedCaps, getModuleBasedCapsOrigin()); + final var mergedCaps = Maps.newHashMapWithExpectedSize( + nonModuleCaps.size() + netconfSessionNonModuleCapabilities.nonModuleCaps.size()); + mergedCaps.putAll(nonModuleCaps); + mergedCaps.putAll(netconfSessionNonModuleCapabilities.nonModuleCaps); + return new NetconfSessionPreferences(ImmutableMap.copyOf(mergedCaps), moduleBasedCaps); } /** * Override current list of non-module based capabilities. * * @param netconfSessionPreferences capabilities to override in this - * * @return new instance of preferences with replaced non-module based capabilities */ public NetconfSessionPreferences replaceNonModuleCaps(final NetconfSessionPreferences netconfSessionPreferences) { - return new NetconfSessionPreferences( - netconfSessionPreferences.getNonModuleBasedCapsOrigin(), getModuleBasedCapsOrigin()); - } - - public static NetconfSessionPreferences fromNetconfSession(final NetconfClientSession session) { - return fromStrings(session.getServerCapabilities()); + return new NetconfSessionPreferences(netconfSessionPreferences.nonModuleCaps, moduleBasedCaps); } private static QName cachedQName(final String namespace, final String revision, final String moduleName) { @@ -209,64 +228,6 @@ public final class NetconfSessionPreferences { return QName.create(XMLNamespace.of(namespace), moduleName).withoutRevision().intern(); } - public static NetconfSessionPreferences fromStrings(final Collection capabilities) { - // we do not know origin of capabilities from only Strings, so we set it to default value - return fromStrings(capabilities, CapabilityOrigin.DeviceAdvertised); - } - - public static NetconfSessionPreferences fromStrings(final Collection capabilities, - final CapabilityOrigin capabilityOrigin) { - final Map moduleBasedCaps = new HashMap<>(); - final Map nonModuleCaps = new HashMap<>(); - - for (final String capability : capabilities) { - nonModuleCaps.put(capability, capabilityOrigin); - final int qmark = capability.indexOf('?'); - if (qmark == -1) { - continue; - } - - final String namespace = capability.substring(0, qmark); - final Iterable queryParams = AMP_SPLITTER.split(capability.substring(qmark + 1)); - final String moduleName = MODULE_PARAM.from(queryParams); - if (Strings.isNullOrEmpty(moduleName)) { - continue; - } - - String revision = REVISION_PARAM.from(queryParams); - if (!Strings.isNullOrEmpty(revision)) { - addModuleQName(moduleBasedCaps, nonModuleCaps, capability, cachedQName(namespace, revision, moduleName), - capabilityOrigin); - continue; - } - - /* - * We have seen devices which mis-escape revision, but the revision may not - * even be there. First check if there is a substring that matches revision. - */ - if (Iterables.any(queryParams, CONTAINS_REVISION)) { - - LOG.debug("Netconf device was not reporting revision correctly, trying to get amp;revision="); - revision = BROKEN_REVISON_PARAM.from(queryParams); - if (Strings.isNullOrEmpty(revision)) { - LOG.warn("Netconf device returned revision incorrectly escaped for {}, ignoring it", capability); - addModuleQName(moduleBasedCaps, nonModuleCaps, capability, - cachedQName(namespace, moduleName), capabilityOrigin); - } else { - addModuleQName(moduleBasedCaps, nonModuleCaps, capability, - cachedQName(namespace, revision, moduleName), capabilityOrigin); - } - continue; - } - - // Fallback, no revision provided for module - addModuleQName(moduleBasedCaps, nonModuleCaps, capability, - cachedQName(namespace, moduleName), capabilityOrigin); - } - - return new NetconfSessionPreferences(ImmutableMap.copyOf(nonModuleCaps), ImmutableMap.copyOf(moduleBasedCaps)); - } - private static void addModuleQName(final Map moduleBasedCaps, final Map nonModuleCaps, final String capability, final QName qualifiedName, final CapabilityOrigin capabilityOrigin) { @@ -274,11 +235,21 @@ public final class NetconfSessionPreferences { nonModuleCaps.remove(capability); } - private final NetconfDeviceCapabilities capabilities = new NetconfDeviceCapabilities(); - - public NetconfDeviceCapabilities getNetconfDeviceCapabilities() { - return capabilities; - } + private static final class ParameterMatcher { + private final Predicate predicate; + private final int skipLength; + ParameterMatcher(final String name) { + predicate = input -> input.startsWith(name); + skipLength = name.length(); + } + String from(final Iterable params) { + final var found = Iterables.tryFind(params, predicate); + if (!found.isPresent()) { + return null; + } + return found.get().substring(skipLength); + } + } }