import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Verify.verify;
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.IETF_NETCONF_MONITORING;
import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_NODEID;
import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_FILTER_NODEID;
import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_FILTER_QNAME;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.NodeFilter;
+import org.w3c.dom.traversal.TreeWalker;
import org.xml.sax.SAXException;
/**
public static final NetconfStateSchemas EMPTY = new NetconfStateSchemas(ImmutableSet.of());
private static final Logger LOG = LoggerFactory.getLogger(NetconfStateSchemas.class);
- private static final YangInstanceIdentifier STATE_SCHEMAS_IDENTIFIER =
- YangInstanceIdentifier.builder().node(NetconfState.QNAME).node(Schemas.QNAME).build();
+ private static final YangInstanceIdentifier STATE_SCHEMAS_IDENTIFIER = YangInstanceIdentifier.builder()
+ .node(NetconfState.QNAME).node(Schemas.QNAME).build();
+ private static final String MONITORING_NAMESPACE = IETF_NETCONF_MONITORING.getNamespace().toString();
private static final @NonNull ContainerNode GET_SCHEMAS_RPC;
static {
if (result == null) {
return Optional.empty();
}
- final Optional<DataContainerChild> rpcResultOpt = ((ContainerNode)result).findChildByArg(NETCONF_DATA_NODEID);
+ // FIXME: unchecked cast
+ final var rpcResultOpt = ((ContainerNode) result).findChildByArg(NETCONF_DATA_NODEID);
if (rpcResultOpt.isEmpty()) {
return Optional.empty();
}
- final DataContainerChild rpcResult = rpcResultOpt.get();
+ final var rpcResult = rpcResultOpt.get();
verify(rpcResult instanceof DOMSourceAnyxmlNode, "Unexpected result %s", rpcResult);
- final NormalizedNode dataNode;
+ // Server may include additional data which we do not understand. Make sure we trim the input before we try
+ // to interpret it.
+ // FIXME: this is something NetconfUtil.transformDOMSourceToNormalizedNode(), and more generally, NormalizedNode
+ // codecs should handle. We really want to a NormalizedNode tree which can be directly queried for known
+ // things while completely ignoring XML content (and hence its semantics) of other elements.
+ final var filteredBody = ietfMonitoringCopy(((DOMSourceAnyxmlNode) rpcResult).body());
+
+ final NormalizedNode dataNode;
try {
- dataNode = NetconfUtil.transformDOMSourceToNormalizedNode(schemaContext,
- ((DOMSourceAnyxmlNode) rpcResult).body()).getResult();
+ dataNode = NetconfUtil.transformDOMSourceToNormalizedNode(schemaContext, filteredBody).getResult();
} catch (XMLStreamException | URISyntaxException | IOException | SAXException e) {
LOG.warn("Failed to transform {}", rpcResult, e);
return Optional.empty();
}
- final Optional<DataContainerChild> nStateNode = ((DataContainerNode) dataNode).findChildByArg(
- toId(NetconfState.QNAME));
+ // FIXME: unchecked cast
+ final var nStateNode = ((DataContainerNode) dataNode).findChildByArg(toId(NetconfState.QNAME));
if (nStateNode.isEmpty()) {
return Optional.empty();
}
+ // FIXME: unchecked cast
return ((DataContainerNode) nStateNode.get()).findChildByArg(toId(Schemas.QNAME));
}
+ @VisibleForTesting
+ static DOMSource ietfMonitoringCopy(final DOMSource domSource) {
+ final var sourceDoc = XmlUtil.newDocument();
+ sourceDoc.appendChild(sourceDoc.importNode(domSource.getNode(), true));
+
+ final var treeWalker = ((DocumentTraversal) sourceDoc).createTreeWalker(sourceDoc.getDocumentElement(),
+ NodeFilter.SHOW_ALL, node -> {
+ final var namespace = node.getNamespaceURI();
+ return namespace == null || MONITORING_NAMESPACE.equals(namespace)
+ ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
+ }, false);
+
+ final var filteredDoc = XmlUtil.newDocument();
+ filteredDoc.appendChild(filteredDoc.importNode(treeWalker.getRoot(), false));
+ final var filteredElement = filteredDoc.getDocumentElement();
+ copyChildren(treeWalker, filteredDoc, filteredElement);
+
+ return new DOMSource(filteredElement);
+ }
+
+ private static void copyChildren(final TreeWalker walker, final Document targetDoc, final Node targetNode) {
+ if (walker.firstChild() != null) {
+ for (var node = walker.getCurrentNode(); node != null; node = walker.nextSibling()) {
+ final var importedNode = targetDoc.importNode(node, false);
+ targetNode.appendChild(importedNode);
+ copyChildren(walker, targetDoc, importedNode);
+ walker.setCurrentNode(node);
+ }
+ }
+ }
+
public static final class RemoteYangSchema {
private final QName qname;
--- /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 org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import javax.xml.transform.dom.DOMSource;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.xml.sax.SAXException;
+
+public class NC881Test {
+ @BeforeClass
+ public static void classSetUp() {
+ XMLUnit.setIgnoreWhitespace(true);
+ }
+
+ @Test
+ public void testFilterDomNamespaces() throws IOException, SAXException {
+ final var source = XmlUtil.readXmlToDocument(
+ getClass().getResourceAsStream("/nc881/netconf-state.xml"));
+ final var expected = XmlUtil.readXmlToDocument(
+ getClass().getResourceAsStream("/nc881/netconf-state-filtered.xml"));
+
+ final var filteredDom = NetconfStateSchemas.ietfMonitoringCopy(new DOMSource(source.getDocumentElement()));
+ final var filtered = XmlUtil.newDocument();
+ filtered.appendChild(filtered.importNode(filteredDom.getNode(), true));
+
+ final var diff = XMLUnit.compareXML(filtered, expected);
+ assertTrue(diff.toString(), diff.similar());
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <schemas>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool</namespace>
+ <location>NETCONF</location>
+ <identifier>threadpool</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-04-09</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:logback:config</namespace>
+ <location>NETCONF</location>
+ <identifier>config-logging</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-07-16</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:model:statistics:types</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-statistics-types</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-09-25</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store
+ </namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-config-dom-datastore</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2014-06-17</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:flow:table:statistics</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-flow-table-statistics</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-12-15</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:meter:service</namespace>
+ <location>NETCONF</location>
+ <identifier>sal-meter</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-09-18</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl
+ </namespace>
+ <location>NETCONF</location>
+ <identifier>toaster-provider-impl</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2014-01-31</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:table:types</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-table-types</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-10-26</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:table:service</namespace>
+ <location>NETCONF</location>
+ <identifier>sal-table</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-10-26</version>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:shutdown</namespace>
+ <location>NETCONF</location>
+ <identifier>shutdown</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-12-18</version>
+ </schema>
+ </schemas>
+ </netconf-state>
+</data>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
+ <schemas>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:threadpool</namespace>
+ <location>NETCONF</location>
+ <identifier>threadpool</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-04-09</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:logback:config</namespace>
+ <location>NETCONF</location>
+ <identifier>config-logging</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-07-16</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:model:statistics:types</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-statistics-types</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-09-25</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store
+ </namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-config-dom-datastore</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2014-06-17</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:flow:table:statistics</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-flow-table-statistics</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-12-15</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:meter:service</namespace>
+ <location>NETCONF</location>
+ <identifier>sal-meter</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-09-18</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl
+ </namespace>
+ <location>NETCONF</location>
+ <identifier>toaster-provider-impl</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2014-01-31</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:table:types</namespace>
+ <location>NETCONF</location>
+ <identifier>opendaylight-table-types</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-10-26</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:table:service</namespace>
+ <location>NETCONF</location>
+ <identifier>sal-table</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-10-26</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ <schema>
+ <namespace>urn:opendaylight:params:xml:ns:yang:controller:shutdown</namespace>
+ <location>NETCONF</location>
+ <identifier>shutdown</identifier>
+ <format xmlns:prefix="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">prefix:yang</format>
+ <version>2013-12-18</version>
+ <semver xmlns="urn:opendaylight:params:xml:ns:netconf">1.0.0</semver>
+ </schema>
+ </schemas>
+ </netconf-state>
+</data>