BUG-2877: Allow hello message with no namespace 26/16926/3
authorMaros Marsalek <mmarsale@cisco.com>
Tue, 24 Mar 2015 09:38:41 +0000 (10:38 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Thu, 26 Mar 2015 09:37:14 +0000 (10:37 +0100)
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 <mmarsale@cisco.com>
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfHelloMessage.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageUtil.java

index 06c695c..f4017fb 100644 (file)
@@ -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 {
index 5cd17a2..404885d 100644 (file)
@@ -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);
index 61b2320..3c6b6cc 100644 (file)
@@ -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<String> extractCapabilitiesFromHello(Document doc) throws NetconfDocumentedException {
         XmlElement responseElement = XmlElement.fromDomDocument(doc);
-        XmlElement capabilitiesElement = responseElement
-                .getOnlyChildElementWithSameNamespace(XmlNetconfConstants.CAPABILITIES);
-        List<XmlElement> caps = capabilitiesElement.getChildElements(XmlNetconfConstants.CAPABILITY);
+        // Extract child element <capabilities> from <hello> with or without(fallback) the same namespace
+        Optional<XmlElement> capabilitiesElement = responseElement
+                .getOnlyChildElementWithSameNamespaceOptionally(XmlNetconfConstants.CAPABILITIES)
+                .or(responseElement
+                        .getOnlyChildElementOptionally(XmlNetconfConstants.CAPABILITIES));
+
+        List<XmlElement> caps = capabilitiesElement.get().getChildElements(XmlNetconfConstants.CAPABILITY);
         return Collections2.transform(caps, new Function<XmlElement, String>() {
 
             @Override

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.