Updating exception and explanation for update node leaves
[cps.git] / cps-service / src / main / java / org / onap / cps / spi / model / DataNodeBuilder.java
index cd6a3a2..4a9957d 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Bell Canada. All rights reserved.
+ *  Modifications Copyright (C) 2021 Pantheon.tech
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -23,13 +24,15 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.spi.exceptions.DataValidationException;
 import org.onap.cps.utils.YangUtils;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
@@ -40,24 +43,38 @@ import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
 @Slf4j
 public class DataNodeBuilder {
 
-    private NormalizedNode normalizedNodeTree;
+    private NormalizedNode<?, ?> normalizedNodeTree;
     private String xpath;
+    private String parentNodeXpath = "";
+    private Map<String, Object> leaves = Collections.emptyMap();
     private Collection<DataNode> childDataNodes = Collections.emptySet();
 
+    /**
+     * To use parent node xpath for creating {@link DataNode}.
+     *
+     * @param parentNodeXpath xpath of a parent node
+     * @return this {@link DataNodeBuilder} object
+     */
+    public DataNodeBuilder withParentNodeXpath(final String parentNodeXpath) {
+        this.parentNodeXpath = parentNodeXpath;
+        return this;
+    }
+
 
-    /** To use {@link NormalizedNode} for creating {@link DataNode}.
+    /**
+     * To use {@link NormalizedNode} for creating {@link DataNode}.
      *
      * @param normalizedNodeTree used for creating the Data Node
-     *
      * @return this {@link DataNodeBuilder} object
      */
-    public DataNodeBuilder withNormalizedNodeTree(final NormalizedNode normalizedNodeTree) {
+    public DataNodeBuilder withNormalizedNodeTree(final NormalizedNode<?, ?> normalizedNodeTree) {
         this.normalizedNodeTree = normalizedNodeTree;
         return this;
     }
 
     /**
      * To use xpath for creating {@link DataNode}.
+     *
      * @param xpath for the data node
      * @return DataNodeBuilder
      */
@@ -66,8 +83,20 @@ public class DataNodeBuilder {
         return this;
     }
 
+    /**
+     * To use attributes for creating {@link DataNode}.
+     *
+     * @param leaves for the data node
+     * @return DataNodeBuilder
+     */
+    public DataNodeBuilder withLeaves(final Map<String, Object> leaves) {
+        this.leaves = leaves;
+        return this;
+    }
+
     /**
      * To specify child nodes needs to be used while creating {@link DataNode}.
+     *
      * @param childDataNodes to be added to the dataNode
      * @return DataNodeBuilder
      */
@@ -91,79 +120,98 @@ public class DataNodeBuilder {
         }
     }
 
+    /**
+     * To build a {@link Collection} of {@link DataNode} objects.
+     *
+     * @return {@link DataNode} {@link Collection}
+     */
+    public Collection<DataNode> buildCollection() {
+        if (normalizedNodeTree != null) {
+            return buildCollectionFromNormalizedNodeTree();
+        } else {
+            return Set.of(buildFromAttributes());
+        }
+    }
+
     private DataNode buildFromAttributes() {
-        final DataNode dataNode = new DataNode();
+        final var dataNode = new DataNode();
         dataNode.setXpath(xpath);
+        dataNode.setLeaves(leaves);
         dataNode.setChildDataNodes(childDataNodes);
         return dataNode;
     }
 
     private DataNode buildFromNormalizedNodeTree() {
-        xpath = YangUtils.buildXpath(normalizedNodeTree.getIdentifier());
-        final DataNode dataNode = new DataNodeBuilder().withXpath(xpath).build();
-        addDataNodeFromNormalizedNode(dataNode, normalizedNodeTree);
-        return dataNode;
+        final Collection<DataNode> dataNodeCollection = buildCollectionFromNormalizedNodeTree();
+        if (!dataNodeCollection.iterator().hasNext()) {
+            throw new DataValidationException(
+                "Unsupported xpath: ", "Unsupported xpath as it is referring to one element");
+        }
+        return dataNodeCollection.iterator().next();
+    }
+
+    private Collection<DataNode> buildCollectionFromNormalizedNodeTree() {
+        final var parentDataNode = new DataNodeBuilder().withXpath(parentNodeXpath).build();
+        addDataNodeFromNormalizedNode(parentDataNode, normalizedNodeTree);
+        return parentDataNode.getChildDataNodes();
     }
 
-    private void addDataNodeFromNormalizedNode(final DataNode currentDataNode,
-        final NormalizedNode normalizedNode) {
+    private static void addDataNodeFromNormalizedNode(final DataNode currentDataNode,
+        final NormalizedNode<?, ?> normalizedNode) {
+
         if (normalizedNode instanceof DataContainerNode) {
-            addYangContainer(currentDataNode, (DataContainerNode) normalizedNode);
+            addYangContainer(currentDataNode, (DataContainerNode<?>) normalizedNode);
         } else if (normalizedNode instanceof MapNode) {
             addDataNodeForEachListElement(currentDataNode, (MapNode) normalizedNode);
         } else if (normalizedNode instanceof ValueNode) {
-            final ValueNode valuesNode = (ValueNode) normalizedNode;
+            final ValueNode<?, ?> valuesNode = (ValueNode<?, ?>) normalizedNode;
             addYangLeaf(currentDataNode, valuesNode.getNodeType().getLocalName(), valuesNode.getValue());
         } else if (normalizedNode instanceof LeafSetNode) {
-            addYangLeafList(currentDataNode, (LeafSetNode) normalizedNode);
+            addYangLeafList(currentDataNode, (LeafSetNode<?>) normalizedNode);
         } else {
-            log.warn("Cannot normalize {}", normalizedNode.getClass());
+            log.warn("Unsupported NormalizedNode type detected: {}", normalizedNode.getClass());
         }
     }
 
-    private void addYangContainer(final DataNode currentDataNode, final DataContainerNode dataContainerNode) {
-        final Collection<NormalizedNode> normalizedChildNodes = dataContainerNode.getValue();
-        for (final NormalizedNode normalizedNode : normalizedChildNodes) {
-            addDataNodeFromNormalizedNode(currentDataNode, normalizedNode);
+    private static void addYangContainer(final DataNode currentDataNode, final DataContainerNode<?> dataContainerNode) {
+        final DataNode dataContainerDataNode =
+            (dataContainerNode.getIdentifier() instanceof YangInstanceIdentifier.AugmentationIdentifier)
+                ? currentDataNode
+                : createAndAddChildDataNode(currentDataNode, YangUtils.buildXpath(dataContainerNode.getIdentifier()));
+        final Collection<DataContainerChild<?, ?>> normalizedChildNodes = dataContainerNode.getValue();
+        for (final NormalizedNode<?, ?> normalizedNode : normalizedChildNodes) {
+            addDataNodeFromNormalizedNode(dataContainerDataNode, normalizedNode);
         }
     }
 
-    private void addYangLeaf(final DataNode currentDataNode, final String leafName, final Object leafValue) {
-        final Map leaves = new ImmutableMap.Builder<String, Object>()
+    private static void addYangLeaf(final DataNode currentDataNode, final String leafName, final Object leafValue) {
+        final Map<String, Object> leaves = new ImmutableMap.Builder<String, Object>()
             .putAll(currentDataNode.getLeaves())
             .put(leafName, leafValue)
             .build();
         currentDataNode.setLeaves(leaves);
     }
 
-    private void addYangLeafList(final DataNode currentDataNode, final LeafSetNode leafSetNode) {
-        final ImmutableSet.Builder builder = new ImmutableSet.Builder<String>();
+    private static void addYangLeafList(final DataNode currentDataNode, final LeafSetNode<?> leafSetNode) {
         final String leafListName = leafSetNode.getNodeType().getLocalName();
-        final Optional<Set<String>> optionalLeafListNames = currentDataNode.getOptionalLeafListNames();
-        if (optionalLeafListNames.isPresent()) {
-            builder.addAll(optionalLeafListNames.get());
-        }
-        builder.add(leafListName);
-        final ImmutableSet leafListNames = builder.build();
-        currentDataNode.setOptionalLeafListNames(Optional.of(leafListNames));
-        final List leafListValues = new LinkedList();
-        for (final NormalizedNode normalizedNode : (Collection<NormalizedNode>) leafSetNode.getValue()) {
-            leafListValues.add(((ValueNode) normalizedNode).getValue());
-        }
+        final List<?> leafListValues = ((Collection<? extends NormalizedNode<?, ?>>) leafSetNode.getValue())
+            .stream()
+            .map(normalizedNode -> ((ValueNode<?, ?>) normalizedNode).getValue())
+            .collect(Collectors.toUnmodifiableList());
         addYangLeaf(currentDataNode, leafListName, leafListValues);
     }
 
-    private void addDataNodeForEachListElement(final DataNode currentDataNode, final MapNode mapNode) {
+    private static void addDataNodeForEachListElement(final DataNode currentDataNode, final MapNode mapNode) {
         final Collection<MapEntryNode> mapEntryNodes = mapNode.getValue();
         for (final MapEntryNode mapEntryNode : mapEntryNodes) {
-            final String xpathChild = YangUtils.buildXpath(mapEntryNode.getIdentifier());
-            final DataNode childDataNode = createAndAddChildDataNode(currentDataNode, xpathChild);
-            addDataNodeFromNormalizedNode(childDataNode, mapEntryNode);
+            addDataNodeFromNormalizedNode(currentDataNode, mapEntryNode);
         }
     }
 
-    private DataNode createAndAddChildDataNode(final DataNode parentDataNode, final String childXpath) {
-        final DataNode newChildDataNode = new DataNodeBuilder().withXpath(xpath + childXpath)
+    private static DataNode createAndAddChildDataNode(final DataNode parentDataNode, final String childXpath) {
+
+        final var newChildDataNode = new DataNodeBuilder()
+            .withXpath(parentDataNode.getXpath() + childXpath)
             .build();
         final Set<DataNode> allChildDataNodes = new ImmutableSet.Builder<DataNode>()
             .addAll(parentDataNode.getChildDataNodes())