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