blob: 7a963f5f375ea967da49ac173ab48654f991f206 [file] [log] [blame]
Vinod Kumar S8c4e6492016-02-05 20:21:19 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Vinod Kumar S8c4e6492016-02-05 20:21:19 +05303 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.yangutils.datamodel;
17
Bharat saraswal96dfef02016-06-16 00:29:12 +053018import java.io.Serializable;
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053019import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
Vidyashree Rama405d2e62016-07-08 20:45:41 +053020import org.onosproject.yangutils.datamodel.utils.Parsable;
21
22import static org.onosproject.yangutils.datamodel.TraversalType.CHILD;
23import static org.onosproject.yangutils.datamodel.TraversalType.PARENT;
24import static org.onosproject.yangutils.datamodel.TraversalType.SIBILING;
25import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.cloneLeaves;
26import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.updateClonedLeavesUnionEnumRef;
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053027
28/**
Bharat saraswald9822e92016-04-05 15:13:44 +053029 * Represents base class of a node in data model tree.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053030 */
Vinod Kumar S427d2932016-04-20 13:02:58 +053031public abstract class YangNode
Gaurav Agrawal72cd1b72016-06-30 13:28:14 +053032 implements Cloneable, Serializable, YangDataNode {
Bharat saraswal96dfef02016-06-16 00:29:12 +053033
34 private static final long serialVersionUID = 806201601L;
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053035
Vinod Kumar S67e7be62016-02-11 20:13:28 +053036 /**
37 * Type of node.
38 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053039 private YangNodeType nodeType;
40
Vinod Kumar S67e7be62016-02-11 20:13:28 +053041 /**
42 * Parent reference.
43 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053044 private YangNode parent;
45
Vinod Kumar S67e7be62016-02-11 20:13:28 +053046 /**
47 * First child reference.
48 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053049 private YangNode child;
50
Vinod Kumar S67e7be62016-02-11 20:13:28 +053051 /**
52 * Next sibling reference.
53 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053054 private YangNode nextSibling;
55
Vinod Kumar S67e7be62016-02-11 20:13:28 +053056 /**
57 * Previous sibling reference.
58 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053059 private YangNode previousSibling;
60
61 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053062 * Returns the nodes name.
Vinod Kumar S38046502016-03-23 15:30:27 +053063 *
64 * @return nodes name
65 */
66 public abstract String getName();
67
68 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053069 * Sets the nodes name.
Vinod Kumar S38046502016-03-23 15:30:27 +053070 *
71 * @param name nodes name
72 */
73 public abstract void setName(String name);
74
75 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053076 * Creates a YANG node object.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053077 */
78 @SuppressWarnings("unused")
79 private YangNode() {
80
81 }
82
83 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053084 * Creates a specific type of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053085 *
86 * @param type of YANG node
87 */
88 protected YangNode(YangNodeType type) {
89 setNodeType(type);
90 }
91
92 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053093 * Returns the node type.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053094 *
95 * @return node type
96 */
97 public YangNodeType getNodeType() {
98 return nodeType;
99 }
100
101 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530102 * Sets the node type.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530103 *
104 * @param nodeType type of node
105 */
106 private void setNodeType(YangNodeType nodeType) {
107 this.nodeType = nodeType;
108 }
109
110 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530111 * Returns the parent of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530112 *
113 * @return parent of node
114 */
115 public YangNode getParent() {
116 return parent;
117 }
118
119 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530120 * Sets the parent of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530121 *
122 * @param parent node
123 */
124 public void setParent(YangNode parent) {
125 this.parent = parent;
126 }
127
128 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530129 * Returns the first child of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530130 *
131 * @return first child of node
132 */
133 public YangNode getChild() {
134 return child;
135 }
136
137 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530138 * Sets the first instance of a child node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530139 *
140 * @param child is only child to be set
141 */
142 public void setChild(YangNode child) {
143 this.child = child;
144 }
145
146 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530147 * Returns the next sibling of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530148 *
149 * @return next sibling of node
150 */
151 public YangNode getNextSibling() {
152 return nextSibling;
153 }
154
155 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530156 * Sets the next sibling of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530157 *
158 * @param sibling YANG node
159 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530160 private void setNextSibling(YangNode sibling) {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530161 nextSibling = sibling;
162 }
163
164 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530165 * Returns the previous sibling.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530166 *
167 * @return previous sibling node
168 */
169 public YangNode getPreviousSibling() {
170 return previousSibling;
171 }
172
173 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530174 * Sets the previous sibling.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530175 *
176 * @param previousSibling points to predecessor sibling
177 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530178 private void setPreviousSibling(YangNode previousSibling) {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530179 this.previousSibling = previousSibling;
180 }
181
182 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530183 * Adds a child node, the children sibling list will be sorted based on node
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530184 * type.
185 *
186 * @param newChild refers to a child to be added
187 * @throws DataModelException due to violation in data model rules
188 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530189 public void addChild(YangNode newChild)
190 throws DataModelException {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530191 if (newChild.getNodeType() == null) {
192 throw new DataModelException("Abstract node cannot be inserted into a tree");
193 }
194
195 if (newChild.getParent() == null) {
196 newChild.setParent(this);
197 } else if (newChild.getParent() != this) {
198 throw new DataModelException("Node is already part of a tree");
199 }
200
201 if (newChild.getChild() != null) {
202 throw new DataModelException("Child to be added is not atomic, it already has a child");
203 }
204
205 if (newChild.getNextSibling() != null) {
206 throw new DataModelException("Child to be added is not atomic, it already has a next sibling");
207 }
208
209 if (newChild.getPreviousSibling() != null) {
210 throw new DataModelException("Child to be added is not atomic, it already has a previous sibling");
211 }
212
213 /* First child to be added */
214 if (getChild() == null) {
215 setChild(newChild);
216 return;
217 }
218
219 YangNode curNode;
220 curNode = getChild();
221
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530222 /*
223 * Get the predecessor child of new child
224 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530225 while (curNode.getNextSibling() != null) {
Vinod Kumar S38046502016-03-23 15:30:27 +0530226
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530227 curNode = curNode.getNextSibling();
228 }
229
230 /* If the new node needs to be the last child */
231 if (curNode.getNextSibling() == null) {
232 curNode.setNextSibling(newChild);
233 newChild.setPreviousSibling(curNode);
Vinod Kumar S427d2932016-04-20 13:02:58 +0530234 }
235 }
Vidyashree Rama405d2e62016-07-08 20:45:41 +0530236
237 /**
238 * Clones the current node contents and create a new node.
239 *
240 * @return cloned node
241 * @throws CloneNotSupportedException clone is not supported by the referred
242 * node
243 */
244 public YangNode clone()
245 throws CloneNotSupportedException {
246 YangNode clonedNode = (YangNode) super.clone();
247 if (clonedNode instanceof YangLeavesHolder) {
248 try {
249 cloneLeaves((YangLeavesHolder) clonedNode);
250 } catch (DataModelException e) {
251 throw new CloneNotSupportedException(e.getMessage());
252 }
253 }
254
255 clonedNode.setParent(null);
256 clonedNode.setChild(null);
257 clonedNode.setNextSibling(null);
258 clonedNode.setPreviousSibling(null);
259 return clonedNode;
260 }
261
262 /**
263 * Clones the subtree from the specified source node to the mentioned target
264 * node. The source and target root node cloning is carried out by the
265 * caller.
266 *
267 * @param srcRootNode source node for sub tree cloning
268 * @param dstRootNode destination node where the sub tree needs to be cloned
269 * @throws DataModelException data model error
270 */
271 public static void cloneSubTree(YangNode srcRootNode, YangNode dstRootNode)
272 throws DataModelException {
273
274 YangNode nextNodeToClone = srcRootNode;
275 TraversalType curTraversal;
276
277 YangNode clonedTreeCurNode = dstRootNode;
278 YangNode newNode = null;
279
280 nextNodeToClone = nextNodeToClone.getChild();
281 if (nextNodeToClone == null) {
282 return;
283 } else {
284 /**
285 * Root level cloning is taken care in the caller.
286 */
287 curTraversal = CHILD;
288 }
289
290 /**
291 * Caller ensures the cloning of the root nodes
292 */
293 try {
294 while (nextNodeToClone != srcRootNode) {
295 if (nextNodeToClone == null) {
296 throw new DataModelException("Internal error: Cloning failed, source tree null pointer reached");
297 }
298 if (curTraversal != PARENT) {
299 newNode = nextNodeToClone.clone();
300 detectCollisionWhileCloning(clonedTreeCurNode, newNode, curTraversal);
301 }
302
303 if (curTraversal == CHILD) {
304
305 /**
306 * add the new node to the cloned tree.
307 */
308 clonedTreeCurNode.addChild(newNode);
309
310 /**
311 * update the cloned tree's traversal current node as the
312 * new node.
313 */
314 clonedTreeCurNode = newNode;
315 } else if (curTraversal == SIBILING) {
316
317 clonedTreeCurNode.addNextSibling(newNode);
318 clonedTreeCurNode = newNode;
319 } else if (curTraversal == PARENT) {
320 if (clonedTreeCurNode instanceof YangLeavesHolder) {
321 updateClonedLeavesUnionEnumRef((YangLeavesHolder) clonedTreeCurNode);
322 }
323 clonedTreeCurNode = clonedTreeCurNode.getParent();
324 }
325
326 if (curTraversal != PARENT && nextNodeToClone.getChild() != null) {
327 curTraversal = CHILD;
328
329 /**
330 * update the traversal's current node.
331 */
332 nextNodeToClone = nextNodeToClone.getChild();
333
334 } else if (nextNodeToClone.getNextSibling() != null) {
335
336 curTraversal = SIBILING;
337
338 nextNodeToClone = nextNodeToClone.getNextSibling();
339 } else {
340 curTraversal = PARENT;
341 nextNodeToClone = nextNodeToClone.getParent();
342 }
343 }
344 } catch (CloneNotSupportedException e) {
345 throw new DataModelException("Failed to clone the tree");
346 }
347
348 }
349
350 /**
351 * Detects collision when the grouping is deep copied to the uses's parent.
352 *
353 * @param currentNode parent/previous sibling node for the new node
354 * @param newNode node which has to be added
355 * @param addAs traversal type of the node
356 * @throws DataModelException data model error
357 */
358 private static void detectCollisionWhileCloning(YangNode currentNode, YangNode newNode, TraversalType addAs)
359 throws DataModelException {
360 if (!(currentNode instanceof CollisionDetector)
361 || !(newNode instanceof Parsable)) {
362 throw new DataModelException("Node in data model tree does not support collision detection");
363 }
364
365 CollisionDetector collisionDetector = (CollisionDetector) currentNode;
366 Parsable parsable = (Parsable) newNode;
367 if (addAs == TraversalType.CHILD) {
368 collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
369 } else if (addAs == TraversalType.SIBILING) {
370 currentNode = currentNode.getParent();
371 if (!(currentNode instanceof CollisionDetector)) {
372 throw new DataModelException("Node in data model tree does not support collision detection");
373 }
374 collisionDetector = (CollisionDetector) currentNode;
375 collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
376 } else {
377 throw new DataModelException("Errored tree cloning");
378 }
379
380 }
381
382 /**
383 * Adds a new next sibling.
384 *
385 * @param newSibling new sibling to be added
386 * @throws DataModelException data model error
387 */
388 private void addNextSibling(YangNode newSibling)
389 throws DataModelException {
390
391 if (newSibling.getNodeType() == null) {
392 throw new DataModelException("Cloned abstract node cannot be inserted into a tree");
393 }
394
395 if (newSibling.getParent() == null) {
396 /**
397 * Since the siblings needs to have a common parent, set the parent
398 * as the current node's parent
399 */
400 newSibling.setParent(getParent());
401
402 } else {
403 throw new DataModelException("Node is already part of a tree, and cannot be added as a sibling");
404 }
405
406 if (newSibling.getPreviousSibling() == null) {
407 newSibling.setPreviousSibling(this);
408 setNextSibling(newSibling);
409 } else {
410 throw new DataModelException("New sibling to be added is not atomic, it already has a previous sibling");
411 }
412
413 if (newSibling.getChild() != null) {
414 throw new DataModelException("Sibling to be added is not atomic, it already has a child");
415 }
416
417 if (newSibling.getNextSibling() != null) {
418 throw new DataModelException("Sibling to be added is not atomic, it already has a next sibling");
419 }
420 }
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530421}