From: Maros Marsalek Date: Tue, 24 Mar 2015 09:38:41 +0000 (+0100) Subject: BUG-2877: Allow hello message with no namespace X-Git-Tag: release/lithium~337^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=b7ed44672b4487c1da3d21fcd6a5a7ccff3eff37 BUG-2877: Allow hello message with no namespace Several network equipments (such as Cisco routers) do not set the namespace attribute (xmlns) in their NETCONF messages. Whether this is valid or not is unclear according to RFC 6241 (NETCONF). This patch improves interoperability by relaxing the constraint for a namespace in NETCONF hello messages. Change-Id: Ie3de4fe454adf0d7dfd3d11eaacacf5d03736502 Signed-off-by: Maros Marsalek --- diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java index 06c695c25a..f4017fbe58 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.netconf.client; -import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -45,6 +45,9 @@ public class NetconfClientSessionNegotiator extends private static final XPathExpression sessionIdXPath = XMLNetconfUtil .compileXPath("/netconf:hello/netconf:session-id"); + private static final XPathExpression sessionIdXPathNoNamespace = XMLNetconfUtil + .compileXPath("/hello/session-id"); + private static final String EXI_1_0_CAPABILITY_MARKER = "exi:1.0"; protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences, @@ -113,16 +116,22 @@ public class NetconfClientSessionNegotiator extends } private long extractSessionId(final Document doc) { - final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE); - Preconditions.checkState(sessionIdNode != null, ""); - String textContent = sessionIdNode.getTextContent(); - if (textContent == null || textContent.equals("")) { - throw new IllegalStateException("Session id not received from server"); + String textContent = getSessionIdWithXPath(doc, sessionIdXPath); + if (Strings.isNullOrEmpty(textContent)) { + textContent = getSessionIdWithXPath(doc, sessionIdXPathNoNamespace); + if (Strings.isNullOrEmpty(textContent)) { + throw new IllegalStateException("Session id not received from server, hello message: " + XmlUtil.toString(doc)); + } } return Long.valueOf(textContent); } + private String getSessionIdWithXPath(final Document doc, final XPathExpression sessionIdXPath) { + final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE); + return sessionIdNode != null ? sessionIdNode.getTextContent() : null; + } + @Override protected NetconfClientSession getSession(final NetconfClientSessionListener sessionListener, final Channel channel, final NetconfHelloMessage message) throws NetconfDocumentedException { diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java index 5cd17a2331..404885db7e 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java @@ -94,9 +94,9 @@ public final class NetconfHelloMessage extends NetconfMessage { private static boolean isHelloMessage(final Document document) { XmlElement element = XmlElement.fromDomElement(document.getDocumentElement()); try { + // accept even if hello has no namespace return element.getName().equals(HELLO_TAG) && - element.hasNamespace() && - element.getNamespace().equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0); + (!element.hasNamespace() || element.getNamespace().equals(XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0)); } catch (MissingNameSpaceException e) { // Cannot happen, since we check for hasNamespace throw new IllegalStateException(e); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java index 61b23202c3..3c6b6ccab9 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.netconf.util.messages; import com.google.common.base.Function; +import com.google.common.base.Optional; import com.google.common.collect.Collections2; import java.util.Collection; import java.util.List; @@ -59,9 +60,13 @@ public final class NetconfMessageUtil { public static Collection extractCapabilitiesFromHello(Document doc) throws NetconfDocumentedException { XmlElement responseElement = XmlElement.fromDomDocument(doc); - XmlElement capabilitiesElement = responseElement - .getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CAPABILITIES); - List caps = capabilitiesElement.getChildElements(XmlNetconfConstants.CAPABILITY); + // Extract child element from with or without(fallback) the same namespace + Optional capabilitiesElement = responseElement + .getOnlyChildElementWithSameNamespaceOptionally(XmlNetconfConstants.CAPABILITIES) + .or(responseElement + .getOnlyChildElementOptionally(XmlNetconfConstants.CAPABILITIES)); + + List caps = capabilitiesElement.get().getChildElements(XmlNetconfConstants.CAPABILITY); return Collections2.transform(caps, new Function() { @Override