Implement subtree filtering using fields
[netconf.git] / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / util / SchemalessRpcStructureTransformer.java
index eed36dbf266606cc6371ce6701bb69ef5fd2a17a..372b356bfb7cd1261bd3becb4cccac0c29c1cd46 100644 (file)
@@ -7,21 +7,28 @@
  */
 package org.opendaylight.netconf.sal.connect.netconf.util;
 
+import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CONFIG_NODEID;
 import static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CONFIG_QNAME;
+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 static org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_OPERATION_QNAME;
+import static org.opendaylight.netconf.util.NetconfUtil.NETCONF_DATA_QNAME;
 
-import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
+import java.util.Locale;
+import java.util.Map.Entry;
+import java.util.Optional;
 import javax.xml.transform.dom.DOMSource;
-import org.opendaylight.controller.config.util.xml.DocumentedException;
-import org.opendaylight.controller.config.util.xml.XmlElement;
-import org.opendaylight.controller.config.util.xml.XmlUtil;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.api.ModifyAction;
+import org.opendaylight.netconf.api.xml.XmlElement;
+import org.opendaylight.netconf.api.xml.XmlUtil;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.ModifyAction;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
@@ -43,19 +50,21 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
      * @return selected data
      */
     @Override
-    public Optional<NormalizedNode<?, ?>> selectFromDataStructure(final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> data,
-                                                                  final YangInstanceIdentifier path) {
-        Preconditions.checkArgument(data instanceof AnyXmlNode);
-        final List<XmlElement> xmlElements = selectMatchingNodes(getSourceElement(((AnyXmlNode)data).getValue()), path);
+    public Optional<NormalizedNode<?, ?>> selectFromDataStructure(
+            final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> data,
+            final YangInstanceIdentifier path) {
+        Preconditions.checkArgument(data instanceof DOMSourceAnyxmlNode);
+        final List<XmlElement> xmlElements = selectMatchingNodes(
+            getSourceElement(((DOMSourceAnyxmlNode)data).getValue()), path);
         final Document result = XmlUtil.newDocument();
-        final QName dataQName = NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
-        final Element dataElement = result.createElementNS(dataQName.getNamespace().toString(), dataQName.getLocalName());
+        final Element dataElement =
+                result.createElementNS(NETCONF_DATA_QNAME.getNamespace().toString(), NETCONF_DATA_QNAME.getLocalName());
         result.appendChild(dataElement);
         for (XmlElement xmlElement : xmlElements) {
             dataElement.appendChild(result.importNode(xmlElement.getDomElement(), true));
         }
-        final AnyXmlNode resultAnyxml = Builders.anyXmlBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(dataQName))
+        final DOMSourceAnyxmlNode resultAnyxml = Builders.anyXmlBuilder()
+                .withNodeIdentifier(NETCONF_DATA_NODEID)
                 .withValue(new DOMSource(result))
                 .build();
         return Optional.of(resultAnyxml);
@@ -70,12 +79,13 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
      * @return config structure
      */
     @Override
-    public AnyXmlNode createEditConfigStructure(final Optional<NormalizedNode<?, ?>> data,
-                                                final YangInstanceIdentifier dataPath, Optional<ModifyAction> operation) {
+    public DOMSourceAnyxmlNode createEditConfigStructure(final Optional<NormalizedNode<?, ?>> data,
+                                                final YangInstanceIdentifier dataPath,
+                                                final Optional<ModifyAction> operation) {
         Preconditions.checkArgument(data.isPresent());
-        Preconditions.checkArgument(data.get() instanceof AnyXmlNode);
+        Preconditions.checkArgument(data.get() instanceof DOMSourceAnyxmlNode);
 
-        final AnyXmlNode anxmlData = (AnyXmlNode) data.get();
+        final DOMSourceAnyxmlNode anxmlData = (DOMSourceAnyxmlNode) data.get();
         final Document document = XmlUtil.newDocument();
         final Element dataNode = (Element) document.importNode(getSourceElement(anxmlData.getValue()), true);
         checkDataValidForPath(dataPath, dataNode);
@@ -85,13 +95,14 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
         document.appendChild(configElement);
 
         final Element parentXmlStructure;
-        if (dataPath.equals(YangInstanceIdentifier.EMPTY)) {
+        if (dataPath.isEmpty()) {
             parentXmlStructure = dataNode;
             configElement.appendChild(parentXmlStructure);
         } else {
             final List<YangInstanceIdentifier.PathArgument> pathArguments = dataPath.getPathArguments();
             //last will be appended later
-            final List<YangInstanceIdentifier.PathArgument> pathWithoutLast = pathArguments.subList(0, pathArguments.size() - 1);
+            final List<YangInstanceIdentifier.PathArgument> pathWithoutLast =
+                    pathArguments.subList(0, pathArguments.size() - 1);
             parentXmlStructure = instanceIdToXmlStructure(pathWithoutLast, configElement);
         }
         if (operation.isPresent()) {
@@ -99,8 +110,7 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
         }
         //append data
         parentXmlStructure.appendChild(document.importNode(dataNode, true));
-        return Builders.anyXmlBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NETCONF_CONFIG_QNAME))
+        return Builders.anyXmlBuilder().withNodeIdentifier(NETCONF_CONFIG_NODEID)
                 .withValue(new DOMSource(document.getDocumentElement()))
                 .build();
     }
@@ -114,29 +124,36 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
     @Override
     public DataContainerChild<?, ?> toFilterStructure(final YangInstanceIdentifier path) {
         final Document document = XmlUtil.newDocument();
-        final QName filterQname = NetconfMessageTransformUtil.NETCONF_FILTER_QNAME;
-        final Element filter = document.createElementNS(filterQname.getNamespace().toString(), filterQname.getLocalName());
-        final Attr a = document.createAttributeNS(filterQname.getNamespace().toString(), "type");
+        final String filterNs = NETCONF_FILTER_QNAME.getNamespace().toString();
+        final Element filter = document.createElementNS(filterNs, NETCONF_FILTER_QNAME.getLocalName());
+        final Attr a = document.createAttributeNS(filterNs, "type");
         a.setTextContent("subtree");
         filter.setAttributeNode(a);
         document.appendChild(filter);
         instanceIdToXmlStructure(path.getPathArguments(), filter);
         return Builders.anyXmlBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(filterQname))
+                .withNodeIdentifier(NETCONF_FILTER_NODEID)
                 .withValue(new DOMSource(document.getDocumentElement()))
                 .build();
     }
 
-    private void checkDataValidForPath(final YangInstanceIdentifier dataPath, final Element dataNode) {
+    @Override
+    public DataContainerChild<?, ?> toFilterStructure(final List<FieldsFilter> fieldsFilters) {
+        // todo: implementation of this feature
+        throw new UnsupportedOperationException(
+                "Creation of filter structure using fields for schemaless mountpoint is not supported");
+    }
+
+    private static void checkDataValidForPath(final YangInstanceIdentifier dataPath, final Element dataNode) {
         //if datapath is empty, consider dataNode to be a root node
-        if (dataPath.equals(YangInstanceIdentifier.EMPTY)) {
+        if (dataPath.isEmpty()) {
             return;
         }
         final XmlElement dataElement = XmlElement.fromDomElement(dataNode);
         final YangInstanceIdentifier.PathArgument lastPathArgument = dataPath.getLastPathArgument();
         final QName nodeType = lastPathArgument.getNodeType();
-        if (!nodeType.getNamespace().toString().equals(dataNode.getNamespaceURI()) ||
-               !nodeType.getLocalName().equals(dataElement.getName())) {
+        if (!nodeType.getNamespace().toString().equals(dataNode.getNamespaceURI())
+                || !nodeType.getLocalName().equals(dataElement.getName())) {
             throw new IllegalStateException(
                     String.format("Can't write data '%s' to path %s", dataNode.getTagName(), dataPath));
         }
@@ -146,14 +163,15 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
 
     }
 
-    private void checkKeyValuesValidForPath(final XmlElement dataElement,
+    private static void checkKeyValuesValidForPath(final XmlElement dataElement,
                                             final YangInstanceIdentifier.PathArgument lastPathArgument) {
         final YangInstanceIdentifier.NodeIdentifierWithPredicates keyedId =
                 (YangInstanceIdentifier.NodeIdentifierWithPredicates) lastPathArgument;
-        final Map<QName, Object> keyValues = keyedId.getKeyValues();
-        for (QName qName : keyValues.keySet()) {
+        for (Entry<QName, Object> entry : keyedId.entrySet()) {
+            QName qualifiedName = entry.getKey();
             final List<XmlElement> key =
-                    dataElement.getChildElementsWithinNamespace(qName.getLocalName(), qName.getNamespace().toString());
+                    dataElement.getChildElementsWithinNamespace(qualifiedName.getLocalName(),
+                            qualifiedName.getNamespace().toString());
             if (key.isEmpty()) {
                 throw new IllegalStateException("No key present in xml");
             }
@@ -164,19 +182,18 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
             try {
                 textContent = key.get(0).getTextContent();
             } catch (DocumentedException e) {
-                throw new IllegalStateException("Key value not present in key element");
+                throw new IllegalStateException("Key value not present in key element", e);
             }
-            if (!keyValues.get(qName).equals(textContent)) {
+            if (!entry.getValue().equals(textContent)) {
                 throw new IllegalStateException("Key value in path not equal to key value in xml");
             }
         }
     }
 
-    private void setOperationAttribute(final Optional<ModifyAction> operation, final Document document,
+    private static void setOperationAttribute(final Optional<ModifyAction> operation, final Document document,
                                        final Element dataNode) {
-        final QName operationQname = NetconfMessageTransformUtil.NETCONF_OPERATION_QNAME;
-        final Attr operationAttribute =
-                document.createAttributeNS(operationQname.getNamespace().toString(), operationQname.getLocalName());
+        final Attr operationAttribute = document.createAttributeNS(NETCONF_OPERATION_QNAME.getNamespace().toString(),
+            NETCONF_OPERATION_QNAME.getLocalName());
         operationAttribute.setTextContent(toOperationString(operation.get()));
         dataNode.setAttributeNode(operationAttribute);
     }
@@ -191,9 +208,11 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
             parent.appendChild(element);
             //if path argument is list id, add also keys to resulting xml
             if (pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
-                YangInstanceIdentifier.NodeIdentifierWithPredicates listNode = (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
-                for (Map.Entry<QName, Object> key : listNode.getKeyValues().entrySet()) {
-                    final Element keyElement = doc.createElementNS(key.getKey().getNamespace().toString(), key.getKey().getLocalName());
+                YangInstanceIdentifier.NodeIdentifierWithPredicates listNode =
+                        (YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument;
+                for (Entry<QName, Object> key : listNode.entrySet()) {
+                    final Element keyElement =
+                            doc.createElementNS(key.getKey().getNamespace().toString(), key.getKey().getLocalName());
                     keyElement.setTextContent(key.getValue().toString());
                     element.appendChild(keyElement);
                 }
@@ -203,7 +222,7 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
         return parent;
     }
 
-    private List<XmlElement> selectMatchingNodes(final Element domElement, final YangInstanceIdentifier path) {
+    private static List<XmlElement> selectMatchingNodes(final Element domElement, final YangInstanceIdentifier path) {
         XmlElement element = XmlElement.fromDomElement(domElement);
         for (YangInstanceIdentifier.PathArgument pathArgument : path.getPathArguments()) {
             List<XmlElement> childElements = element.getChildElements(pathArgument.getNodeType().getLocalName());
@@ -217,7 +236,7 @@ class SchemalessRpcStructureTransformer implements RpcStructureTransformer {
     }
 
     private static String toOperationString(final ModifyAction operation) {
-        return operation.name().toLowerCase();
+        return operation.name().toLowerCase(Locale.ROOT);
     }
 
     private static Element getSourceElement(final DOMSource source) {