762e61ac591ef75cf6eca8d8e389cf832c11cfe6
[cps.git] / cps-service / src / main / java / org / onap / cps / spi / model / DataNodeBuilder.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Bell Canada. All rights reserved.
4  *  Modifications Copyright (C) 2021 Pantheon.tech
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.spi.model;
22
23 import com.google.common.collect.ImmutableMap;
24 import com.google.common.collect.ImmutableSet;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.stream.Collectors;
31 import lombok.extern.slf4j.Slf4j;
32 import org.onap.cps.utils.YangUtils;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
34 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
35 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
41
42 @Slf4j
43 public class DataNodeBuilder {
44
45     private NormalizedNode<?, ?> normalizedNodeTree;
46     private String xpath;
47     private String parentNodeXpath = "";
48     private Map<String, Object> leaves = Collections.emptyMap();
49     private Collection<DataNode> childDataNodes = Collections.emptySet();
50
51     /**
52      * To use parent node xpath for creating {@link DataNode}.
53      *
54      * @param parentNodeXpath xpath of a parent node
55      * @return this {@link DataNodeBuilder} object
56      */
57     public DataNodeBuilder withParentNodeXpath(final String parentNodeXpath) {
58         this.parentNodeXpath = parentNodeXpath;
59         return this;
60     }
61
62
63     /**
64      * To use {@link NormalizedNode} for creating {@link DataNode}.
65      *
66      * @param normalizedNodeTree used for creating the Data Node
67      * @return this {@link DataNodeBuilder} object
68      */
69     public DataNodeBuilder withNormalizedNodeTree(final NormalizedNode<?, ?> normalizedNodeTree) {
70         this.normalizedNodeTree = normalizedNodeTree;
71         return this;
72     }
73
74     /**
75      * To use xpath for creating {@link DataNode}.
76      *
77      * @param xpath for the data node
78      * @return DataNodeBuilder
79      */
80     public DataNodeBuilder withXpath(final String xpath) {
81         this.xpath = xpath;
82         return this;
83     }
84
85     /**
86      * To use attributes for creating {@link DataNode}.
87      *
88      * @param leaves for the data node
89      * @return DataNodeBuilder
90      */
91     public DataNodeBuilder withLeaves(final Map<String, Object> leaves) {
92         this.leaves = leaves;
93         return this;
94     }
95
96     /**
97      * To specify child nodes needs to be used while creating {@link DataNode}.
98      *
99      * @param childDataNodes to be added to the dataNode
100      * @return DataNodeBuilder
101      */
102     public DataNodeBuilder withChildDataNodes(final Collection<DataNode> childDataNodes) {
103         // Added as this is being set from test cases .
104         // Open for suggestions
105         this.childDataNodes = childDataNodes;
106         return this;
107     }
108
109     /**
110      * To create the {@link DataNode}.
111      *
112      * @return {@link DataNode}
113      */
114     public DataNode build() {
115         if (normalizedNodeTree != null) {
116             return buildFromNormalizedNodeTree();
117         } else {
118             return buildFromAttributes();
119         }
120     }
121
122     /**
123      * To build a {@link Collection} of {@link DataNode} objects.
124      *
125      * @return {@link DataNode} {@link Collection}
126      */
127     public Collection<DataNode> buildCollection() {
128         if (normalizedNodeTree != null) {
129             return buildCollectionFromNormalizedNodeTree();
130         } else {
131             return Set.of(buildFromAttributes());
132         }
133     }
134
135     private DataNode buildFromAttributes() {
136         final var dataNode = new DataNode();
137         dataNode.setXpath(xpath);
138         dataNode.setLeaves(leaves);
139         dataNode.setChildDataNodes(childDataNodes);
140         return dataNode;
141     }
142
143     private DataNode buildFromNormalizedNodeTree() {
144         final Collection<DataNode> dataNodeCollection = buildCollectionFromNormalizedNodeTree();
145         return dataNodeCollection.iterator().next();
146     }
147
148     private Collection<DataNode> buildCollectionFromNormalizedNodeTree() {
149         final var parentDataNode = new DataNodeBuilder().withXpath(parentNodeXpath).build();
150         addDataNodeFromNormalizedNode(parentDataNode, normalizedNodeTree);
151         return parentDataNode.getChildDataNodes();
152     }
153
154     private static void addDataNodeFromNormalizedNode(final DataNode currentDataNode,
155         final NormalizedNode<?, ?> normalizedNode) {
156
157         if (normalizedNode instanceof DataContainerNode) {
158             addYangContainer(currentDataNode, (DataContainerNode<?>) normalizedNode);
159         } else if (normalizedNode instanceof MapNode) {
160             addDataNodeForEachListElement(currentDataNode, (MapNode) normalizedNode);
161         } else if (normalizedNode instanceof ValueNode) {
162             final ValueNode<?, ?> valuesNode = (ValueNode<?, ?>) normalizedNode;
163             addYangLeaf(currentDataNode, valuesNode.getNodeType().getLocalName(), valuesNode.getValue());
164         } else if (normalizedNode instanceof LeafSetNode) {
165             addYangLeafList(currentDataNode, (LeafSetNode<?>) normalizedNode);
166         } else {
167             log.warn("Unsupported NormalizedNode type detected: {}", normalizedNode.getClass());
168         }
169     }
170
171     private static void addYangContainer(final DataNode currentDataNode, final DataContainerNode<?> dataContainerNode) {
172         final DataNode dataContainerDataNode =
173             (dataContainerNode.getIdentifier() instanceof YangInstanceIdentifier.AugmentationIdentifier)
174                 ? currentDataNode
175                 : createAndAddChildDataNode(currentDataNode, YangUtils.buildXpath(dataContainerNode.getIdentifier()));
176         final Collection<DataContainerChild<?, ?>> normalizedChildNodes = dataContainerNode.getValue();
177         for (final NormalizedNode<?, ?> normalizedNode : normalizedChildNodes) {
178             addDataNodeFromNormalizedNode(dataContainerDataNode, normalizedNode);
179         }
180     }
181
182     private static void addYangLeaf(final DataNode currentDataNode, final String leafName, final Object leafValue) {
183         final Map<String, Object> leaves = new ImmutableMap.Builder<String, Object>()
184             .putAll(currentDataNode.getLeaves())
185             .put(leafName, leafValue)
186             .build();
187         currentDataNode.setLeaves(leaves);
188     }
189
190     private static void addYangLeafList(final DataNode currentDataNode, final LeafSetNode<?> leafSetNode) {
191         final String leafListName = leafSetNode.getNodeType().getLocalName();
192         final List<?> leafListValues = ((Collection<? extends NormalizedNode<?, ?>>) leafSetNode.getValue())
193             .stream()
194             .map(normalizedNode -> ((ValueNode<?, ?>) normalizedNode).getValue())
195             .collect(Collectors.toUnmodifiableList());
196         addYangLeaf(currentDataNode, leafListName, leafListValues);
197     }
198
199     private static void addDataNodeForEachListElement(final DataNode currentDataNode, final MapNode mapNode) {
200         final Collection<MapEntryNode> mapEntryNodes = mapNode.getValue();
201         for (final MapEntryNode mapEntryNode : mapEntryNodes) {
202             addDataNodeFromNormalizedNode(currentDataNode, mapEntryNode);
203         }
204     }
205
206     private static DataNode createAndAddChildDataNode(final DataNode parentDataNode, final String childXpath) {
207
208         final var newChildDataNode = new DataNodeBuilder()
209             .withXpath(parentDataNode.getXpath() + childXpath)
210             .build();
211         final Set<DataNode> allChildDataNodes = new ImmutableSet.Builder<DataNode>()
212             .addAll(parentDataNode.getChildDataNodes())
213             .add(newChildDataNode)
214             .build();
215         parentDataNode.setChildDataNodes(allChildDataNodes);
216         return newChildDataNode;
217     }
218
219 }