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
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.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.spi.model;
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;
30 import java.util.stream.Collectors;
31 import lombok.extern.slf4j.Slf4j;
32 import org.onap.cps.spi.exceptions.DataValidationException;
33 import org.onap.cps.utils.YangUtils;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
36 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
44 public class DataNodeBuilder {
46 private NormalizedNode<?, ?> normalizedNodeTree;
48 private String parentNodeXpath = "";
49 private Map<String, Object> leaves = Collections.emptyMap();
50 private Collection<DataNode> childDataNodes = Collections.emptySet();
53 * To use parent node xpath for creating {@link DataNode}.
55 * @param parentNodeXpath xpath of a parent node
56 * @return this {@link DataNodeBuilder} object
58 public DataNodeBuilder withParentNodeXpath(final String parentNodeXpath) {
59 this.parentNodeXpath = parentNodeXpath;
65 * To use {@link NormalizedNode} for creating {@link DataNode}.
67 * @param normalizedNodeTree used for creating the Data Node
68 * @return this {@link DataNodeBuilder} object
70 public DataNodeBuilder withNormalizedNodeTree(final NormalizedNode<?, ?> normalizedNodeTree) {
71 this.normalizedNodeTree = normalizedNodeTree;
76 * To use xpath for creating {@link DataNode}.
78 * @param xpath for the data node
79 * @return DataNodeBuilder
81 public DataNodeBuilder withXpath(final String xpath) {
87 * To use attributes for creating {@link DataNode}.
89 * @param leaves for the data node
90 * @return DataNodeBuilder
92 public DataNodeBuilder withLeaves(final Map<String, Object> leaves) {
98 * To specify child nodes needs to be used while creating {@link DataNode}.
100 * @param childDataNodes to be added to the dataNode
101 * @return DataNodeBuilder
103 public DataNodeBuilder withChildDataNodes(final Collection<DataNode> childDataNodes) {
104 // Added as this is being set from test cases .
105 // Open for suggestions
106 this.childDataNodes = childDataNodes;
111 * To create the {@link DataNode}.
113 * @return {@link DataNode}
115 public DataNode build() {
116 if (normalizedNodeTree != null) {
117 return buildFromNormalizedNodeTree();
119 return buildFromAttributes();
124 * To build a {@link Collection} of {@link DataNode} objects.
126 * @return {@link DataNode} {@link Collection}
128 public Collection<DataNode> buildCollection() {
129 if (normalizedNodeTree != null) {
130 return buildCollectionFromNormalizedNodeTree();
132 return Set.of(buildFromAttributes());
136 private DataNode buildFromAttributes() {
137 final var dataNode = new DataNode();
138 dataNode.setXpath(xpath);
139 dataNode.setLeaves(leaves);
140 dataNode.setChildDataNodes(childDataNodes);
144 private DataNode buildFromNormalizedNodeTree() {
145 final Collection<DataNode> dataNodeCollection = buildCollectionFromNormalizedNodeTree();
146 if (!dataNodeCollection.iterator().hasNext()) {
147 throw new DataValidationException(
148 "Unsupported xpath: ", "Unsupported xpath as it is referring to one element");
150 return dataNodeCollection.iterator().next();
153 private Collection<DataNode> buildCollectionFromNormalizedNodeTree() {
154 final var parentDataNode = new DataNodeBuilder().withXpath(parentNodeXpath).build();
155 addDataNodeFromNormalizedNode(parentDataNode, normalizedNodeTree);
156 return parentDataNode.getChildDataNodes();
159 private static void addDataNodeFromNormalizedNode(final DataNode currentDataNode,
160 final NormalizedNode<?, ?> normalizedNode) {
162 if (normalizedNode instanceof DataContainerNode) {
163 addYangContainer(currentDataNode, (DataContainerNode<?>) normalizedNode);
164 } else if (normalizedNode instanceof MapNode) {
165 addDataNodeForEachListElement(currentDataNode, (MapNode) normalizedNode);
166 } else if (normalizedNode instanceof ValueNode) {
167 final ValueNode<?, ?> valuesNode = (ValueNode<?, ?>) normalizedNode;
168 addYangLeaf(currentDataNode, valuesNode.getNodeType().getLocalName(), valuesNode.getValue());
169 } else if (normalizedNode instanceof LeafSetNode) {
170 addYangLeafList(currentDataNode, (LeafSetNode<?>) normalizedNode);
172 log.warn("Unsupported NormalizedNode type detected: {}", normalizedNode.getClass());
176 private static void addYangContainer(final DataNode currentDataNode, final DataContainerNode<?> dataContainerNode) {
177 final DataNode dataContainerDataNode =
178 (dataContainerNode.getIdentifier() instanceof YangInstanceIdentifier.AugmentationIdentifier)
180 : createAndAddChildDataNode(currentDataNode, YangUtils.buildXpath(dataContainerNode.getIdentifier()));
181 final Collection<DataContainerChild<?, ?>> normalizedChildNodes = dataContainerNode.getValue();
182 for (final NormalizedNode<?, ?> normalizedNode : normalizedChildNodes) {
183 addDataNodeFromNormalizedNode(dataContainerDataNode, normalizedNode);
187 private static void addYangLeaf(final DataNode currentDataNode, final String leafName, final Object leafValue) {
188 final Map<String, Object> leaves = new ImmutableMap.Builder<String, Object>()
189 .putAll(currentDataNode.getLeaves())
190 .put(leafName, leafValue)
192 currentDataNode.setLeaves(leaves);
195 private static void addYangLeafList(final DataNode currentDataNode, final LeafSetNode<?> leafSetNode) {
196 final String leafListName = leafSetNode.getNodeType().getLocalName();
197 final List<?> leafListValues = ((Collection<? extends NormalizedNode<?, ?>>) leafSetNode.getValue())
199 .map(normalizedNode -> ((ValueNode<?, ?>) normalizedNode).getValue())
200 .collect(Collectors.toUnmodifiableList());
201 addYangLeaf(currentDataNode, leafListName, leafListValues);
204 private static void addDataNodeForEachListElement(final DataNode currentDataNode, final MapNode mapNode) {
205 final Collection<MapEntryNode> mapEntryNodes = mapNode.getValue();
206 for (final MapEntryNode mapEntryNode : mapEntryNodes) {
207 addDataNodeFromNormalizedNode(currentDataNode, mapEntryNode);
211 private static DataNode createAndAddChildDataNode(final DataNode parentDataNode, final String childXpath) {
213 final var newChildDataNode = new DataNodeBuilder()
214 .withXpath(parentDataNode.getXpath() + childXpath)
216 final Set<DataNode> allChildDataNodes = new ImmutableSet.Builder<DataNode>()
217 .addAll(parentDataNode.getChildDataNodes())
218 .add(newChildDataNode)
220 parentDataNode.setChildDataNodes(allChildDataNodes);
221 return newChildDataNode;