BUG-2184 Fix subtree filtering for identity-ref leaves 65/12165/1
authorMaros Marsalek <mmarsale@cisco.com>
Wed, 22 Oct 2014 15:49:19 +0000 (17:49 +0200)
committerMaros Marsalek <mmarsale@cisco.com>
Wed, 22 Oct 2014 15:49:38 +0000 (17:49 +0200)
Change-Id: I7d367c793a461ae26f56ddf611f7e45a723f28fc
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/SubtreeFilter.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/SubtreeFilterTest.java
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java

index 6e8158413388d555e9d102354854f684f336d733..42a8bae4484b93a3ed4689223cbf34a9aacbd986 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.controller.netconf.impl;
 
 import com.google.common.base.Optional;
 import java.io.IOException;
+import java.util.Map;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.mapping.AbstractNetconfOperation.OperationNameAndNamespace;
@@ -73,7 +74,7 @@ public class SubtreeFilter {
         return result;
     }
 
-    private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) {
+    private static void addSubtree(XmlElement filter, XmlElement src, XmlElement dst) throws NetconfDocumentedException {
         for (XmlElement srcChild : src.getChildElements()) {
             for (XmlElement filterChild : filter.getChildElements()) {
                 addSubtree2(filterChild, srcChild, dst);
@@ -81,7 +82,7 @@ public class SubtreeFilter {
         }
     }
 
-    private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) {
+    private static MatchingResult addSubtree2(XmlElement filter, XmlElement src, XmlElement dstParent) throws NetconfDocumentedException {
         Document document = dstParent.getDomElement().getOwnerDocument();
         MatchingResult matches = matches(src, filter);
         if (matches != MatchingResult.NO_MATCH && matches != MatchingResult.CONTENT_MISMATCH) {
@@ -123,7 +124,7 @@ public class SubtreeFilter {
      * Shallow compare src node to filter: tag name and namespace must match.
      * If filter node has no children and has text content, it also must match.
      */
-    private static MatchingResult matches(XmlElement src, XmlElement filter) {
+    private static MatchingResult matches(XmlElement src, XmlElement filter) throws NetconfDocumentedException {
         boolean tagMatch = src.getName().equals(filter.getName()) &&
                 src.getNamespaceOptionally().equals(filter.getNamespaceOptionally());
         MatchingResult result = null;
@@ -131,7 +132,7 @@ public class SubtreeFilter {
             // match text content
             Optional<String> maybeText = filter.getOnlyTextContentOptionally();
             if (maybeText.isPresent()) {
-                if (maybeText.equals(src.getOnlyTextContentOptionally())) {
+                if (maybeText.equals(src.getOnlyTextContentOptionally()) || prefixedContentMatches(filter, src)) {
                     result = MatchingResult.CONTENT_MATCH;
                 } else {
                     result = MatchingResult.CONTENT_MISMATCH;
@@ -159,10 +160,30 @@ public class SubtreeFilter {
         if (result == null) {
             result = MatchingResult.NO_MATCH;
         }
-        logger.debug("Matching {} to {} resulted in {}", src, filter, tagMatch);
+        logger.debug("Matching {} to {} resulted in {}", src, filter, result);
         return result;
     }
 
+    private static boolean prefixedContentMatches(final XmlElement filter, final XmlElement src) throws NetconfDocumentedException {
+        final Map.Entry<String, String> prefixToNamespaceOfFilter = filter.findNamespaceOfTextContent();
+        final Map.Entry<String, String> prefixToNamespaceOfSrc = src.findNamespaceOfTextContent();
+
+        final String prefix = prefixToNamespaceOfFilter.getKey();
+        // If this is not a prefixed content, we do not need to continue since content do not match
+        if(prefix.equals(XmlElement.DEFAULT_NAMESPACE_PREFIX)) {
+            return false;
+        }
+        // Namespace mismatch
+        if(!prefixToNamespaceOfFilter.getValue().equals(prefixToNamespaceOfSrc.getValue())) {
+            return false;
+        }
+
+        final String unprefixedFilterContent = filter.getTextContent().substring(prefix.length());
+        final String unprefixedSrcCOntnet = src.getTextContent().substring(prefix.length());
+        // Finally compare unprefixed content
+        return unprefixedFilterContent.equals(unprefixedSrcCOntnet);
+    }
+
     enum MatchingResult {
         NO_MATCH, TAG_MATCH, CONTENT_MATCH, CONTENT_MISMATCH
     }
index b11834386e0f76e761924ee881977cbc5d0b0aef..5d9470750e54053423b8bb871192fafedf9bf53b 100644 (file)
@@ -36,7 +36,7 @@ public class SubtreeFilterTest {
     @Parameters
     public static Collection<Object[]> data() {
         List<Object[]> result = new ArrayList<>();
-        for (int i = 0; i <= 8; i++) {
+        for (int i = 0; i <= 9; i++) {
             result.add(new Object[]{i});
         }
         return result;
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/post-filter.xml
new file mode 100644 (file)
index 0000000..afe9655
--- /dev/null
@@ -0,0 +1,14 @@
+<rpc-reply message-id="5"
+           xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <data>
+    <top xmlns="http://example.com/schema/1.2/config">
+      <users>
+        <user>
+          <name>fred</name>
+            <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+          <full-name>Fred Flintstone</full-name>
+        </user>
+      </users>
+    </top>
+  </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/pre-filter.xml
new file mode 100644 (file)
index 0000000..eca3241
--- /dev/null
@@ -0,0 +1,40 @@
+<rpc-reply message-id="5" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <data>
+    <top xmlns="http://example.com/schema/1.2/config">
+      <users>
+        <user>
+          <name>root</name>
+          <type>superuser</type>
+          <full-name>Charlie Root</full-name>
+          <company-info>
+            <dept>1</dept>
+            <id>1</id>
+          </company-info>
+        </user>
+        <user>
+          <name>fred</name>
+          <type xmlns:x="http://java.sun.com/dtd/properties.dtd">x:admin</type>
+          <full-name>Fred Flintstone</full-name>
+          <company-info>
+            <dept>2</dept>
+            <id>2</id>
+          </company-info>
+        </user>
+        <user>
+          <name>barney</name>
+          <type>admin</type>
+          <full-name>Barney Rubble</full-name>
+          <company-info>
+            <dept>2</dept>
+            <id>3</id>
+          </company-info>
+        </user>
+      </users>
+      <groups>
+        <group>
+          <name>admin</name>
+        </group>
+      </groups>
+    </top>
+  </data>
+</rpc-reply>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml b/opendaylight/netconf/netconf-impl/src/test/resources/subtree/9/request.xml
new file mode 100644 (file)
index 0000000..47da0fe
--- /dev/null
@@ -0,0 +1,19 @@
+<rpc message-id="5"
+     xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+  <get-config>
+    <source>
+      <running/>
+    </source>
+    <filter type="subtree">
+      <top xmlns="http://example.com/schema/1.2/config">
+        <users>
+          <user>
+            <name>fred</name>
+              <type xmlns:a="http://java.sun.com/dtd/properties.dtd">a:admin</type>
+            <full-name/>
+          </user>
+        </users>
+      </top>
+    </filter>
+  </get-config>
+</rpc>
\ No newline at end of file
index 78efe7e9723154bd218bafa5d248af0329fb567d..3c63204881aa9ea0ef3e0909ad302e73187d5b31 100644 (file)
@@ -37,6 +37,8 @@ import org.xml.sax.SAXException;
 
 public final class XmlElement {
 
+    public static final String DEFAULT_NAMESPACE_PREFIX = "";
+
     private final Element element;
     private static final Logger logger = LoggerFactory.getLogger(XmlElement.class);
 
@@ -72,16 +74,16 @@ public final class XmlElement {
         return xmlElement;
     }
 
-    private static Map<String, String> extractNamespaces(Element typeElement) throws NetconfDocumentedException {
+    private Map<String, String> extractNamespaces() throws NetconfDocumentedException {
         Map<String, String> namespaces = new HashMap<>();
-        NamedNodeMap attributes = typeElement.getAttributes();
+        NamedNodeMap attributes = element.getAttributes();
         for (int i = 0; i < attributes.getLength(); i++) {
             Node attribute = attributes.item(i);
             String attribKey = attribute.getNodeName();
             if (attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
                 String prefix;
                 if (attribKey.equals(XmlUtil.XMLNS_ATTRIBUTE_KEY)) {
-                    prefix = "";
+                    prefix = DEFAULT_NAMESPACE_PREFIX;
                 } else {
                     if (!attribKey.startsWith(XmlUtil.XMLNS_ATTRIBUTE_KEY + ":")){
                         throw new NetconfDocumentedException("Attribute doesn't start with :",
@@ -94,6 +96,15 @@ public final class XmlElement {
                 namespaces.put(prefix, attribute.getNodeValue());
             }
         }
+
+        // namespace does not have to be defined on this element but inherited
+        if(!namespaces.containsKey(DEFAULT_NAMESPACE_PREFIX)) {
+            Optional<String> namespaceOptionally = getNamespaceOptionally();
+            if(namespaceOptionally.isPresent()) {
+                namespaces.put(DEFAULT_NAMESPACE_PREFIX, namespaceOptionally.get());
+            }
+        }
+
         return namespaces;
     }
 
@@ -132,7 +143,7 @@ public final class XmlElement {
     }
 
     public String getName() {
-        if (element.getLocalName()!=null && !element.getLocalName().equals("")){
+        if (element.getLocalName()!=null && !element.getLocalName().equals(DEFAULT_NAMESPACE_PREFIX)){
             return element.getLocalName();
         }
         return element.getTagName();
@@ -327,7 +338,7 @@ public final class XmlElement {
     public String getTextContent() throws NetconfDocumentedException {
         NodeList childNodes = element.getChildNodes();
         if (childNodes.getLength() == 0) {
-            return "";
+            return DEFAULT_NAMESPACE_PREFIX;
         }
         for(int i = 0; i < childNodes.getLength(); i++) {
             Node textChild = childNodes.item(i);
@@ -356,7 +367,7 @@ public final class XmlElement {
 
     public String getNamespaceAttribute() throws MissingNameSpaceException {
         String attribute = element.getAttribute(XmlUtil.XMLNS_ATTRIBUTE_KEY);
-        if (attribute == null || attribute.equals("")){
+        if (attribute == null || attribute.equals(DEFAULT_NAMESPACE_PREFIX)){
             throw new MissingNameSpaceException(String.format("Element %s must specify namespace",
                     toString()),
                     NetconfDocumentedException.ErrorType.application,
@@ -415,14 +426,14 @@ public final class XmlElement {
      * is found value will be null.
      */
     public Map.Entry<String/* prefix */, String/* namespace */> findNamespaceOfTextContent() throws NetconfDocumentedException {
-        Map<String, String> namespaces = extractNamespaces(element);
+        Map<String, String> namespaces = extractNamespaces();
         String textContent = getTextContent();
         int indexOfColon = textContent.indexOf(':');
         String prefix;
         if (indexOfColon > -1) {
             prefix = textContent.substring(0, indexOfColon);
         } else {
-            prefix = "";
+            prefix = DEFAULT_NAMESPACE_PREFIX;
         }
         if (!namespaces.containsKey(prefix)) {
             throw new IllegalArgumentException("Cannot find namespace for " + XmlUtil.toString(element) + ". Prefix from content is "