blob: 811c76e4e8a628481bde73e9b84161e49a51e41e [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
18import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
janani b4e53f9b2016-04-26 18:49:20 +053019import org.onosproject.yangutils.parser.Parsable;
Vinod Kumar S427d2932016-04-20 13:02:58 +053020import org.onosproject.yangutils.translator.tojava.TraversalType;
21
22import static org.onosproject.yangutils.translator.tojava.TraversalType.CHILD;
23import static org.onosproject.yangutils.translator.tojava.TraversalType.PARENT;
24import static org.onosproject.yangutils.translator.tojava.TraversalType.SIBILING;
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053025
26/**
Bharat saraswald9822e92016-04-05 15:13:44 +053027 * Represents base class of a node in data model tree.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053028 */
Vinod Kumar S427d2932016-04-20 13:02:58 +053029public abstract class YangNode
30 implements Cloneable {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053031
Vinod Kumar S67e7be62016-02-11 20:13:28 +053032 /**
33 * Type of node.
34 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053035 private YangNodeType nodeType;
36
Vinod Kumar S67e7be62016-02-11 20:13:28 +053037 /**
38 * Parent reference.
39 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053040 private YangNode parent;
41
Vinod Kumar S67e7be62016-02-11 20:13:28 +053042 /**
43 * First child reference.
44 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053045 private YangNode child;
46
Vinod Kumar S67e7be62016-02-11 20:13:28 +053047 /**
48 * Next sibling reference.
49 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053050 private YangNode nextSibling;
51
Vinod Kumar S67e7be62016-02-11 20:13:28 +053052 /**
53 * Previous sibling reference.
54 */
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053055 private YangNode previousSibling;
56
57 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053058 * Returns the nodes name.
Vinod Kumar S38046502016-03-23 15:30:27 +053059 *
60 * @return nodes name
61 */
62 public abstract String getName();
63
64 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053065 * Sets the nodes name.
Vinod Kumar S38046502016-03-23 15:30:27 +053066 *
67 * @param name nodes name
68 */
69 public abstract void setName(String name);
70
71 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053072 * Creates a YANG node object.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053073 */
74 @SuppressWarnings("unused")
75 private YangNode() {
76
77 }
78
79 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053080 * Creates a specific type of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053081 *
82 * @param type of YANG node
83 */
84 protected YangNode(YangNodeType type) {
85 setNodeType(type);
86 }
87
88 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053089 * Returns the node type.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053090 *
91 * @return node type
92 */
93 public YangNodeType getNodeType() {
94 return nodeType;
95 }
96
97 /**
Bharat saraswald9822e92016-04-05 15:13:44 +053098 * Sets the node type.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +053099 *
100 * @param nodeType type of node
101 */
102 private void setNodeType(YangNodeType nodeType) {
103 this.nodeType = nodeType;
104 }
105
106 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530107 * Returns the parent of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530108 *
109 * @return parent of node
110 */
111 public YangNode getParent() {
112 return parent;
113 }
114
115 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530116 * Sets the parent of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530117 *
118 * @param parent node
119 */
120 public void setParent(YangNode parent) {
121 this.parent = parent;
122 }
123
124 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530125 * Returns the first child of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530126 *
127 * @return first child of node
128 */
129 public YangNode getChild() {
130 return child;
131 }
132
133 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530134 * Sets the first instance of a child node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530135 *
136 * @param child is only child to be set
137 */
138 public void setChild(YangNode child) {
139 this.child = child;
140 }
141
142 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530143 * Returns the next sibling of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530144 *
145 * @return next sibling of node
146 */
147 public YangNode getNextSibling() {
148 return nextSibling;
149 }
150
151 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530152 * Sets the next sibling of node.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530153 *
154 * @param sibling YANG node
155 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530156 private void setNextSibling(YangNode sibling) {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530157 nextSibling = sibling;
158 }
159
160 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530161 * Returns the previous sibling.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530162 *
163 * @return previous sibling node
164 */
165 public YangNode getPreviousSibling() {
166 return previousSibling;
167 }
168
169 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530170 * Sets the previous sibling.
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530171 *
172 * @param previousSibling points to predecessor sibling
173 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530174 private void setPreviousSibling(YangNode previousSibling) {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530175 this.previousSibling = previousSibling;
176 }
177
178 /**
Bharat saraswald9822e92016-04-05 15:13:44 +0530179 * Adds a child node, the children sibling list will be sorted based on node
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530180 * type.
181 *
182 * @param newChild refers to a child to be added
183 * @throws DataModelException due to violation in data model rules
184 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530185 public void addChild(YangNode newChild)
186 throws DataModelException {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530187 if (newChild.getNodeType() == null) {
188 throw new DataModelException("Abstract node cannot be inserted into a tree");
189 }
190
191 if (newChild.getParent() == null) {
192 newChild.setParent(this);
193 } else if (newChild.getParent() != this) {
194 throw new DataModelException("Node is already part of a tree");
195 }
196
197 if (newChild.getChild() != null) {
198 throw new DataModelException("Child to be added is not atomic, it already has a child");
199 }
200
201 if (newChild.getNextSibling() != null) {
202 throw new DataModelException("Child to be added is not atomic, it already has a next sibling");
203 }
204
205 if (newChild.getPreviousSibling() != null) {
206 throw new DataModelException("Child to be added is not atomic, it already has a previous sibling");
207 }
208
209 /* First child to be added */
210 if (getChild() == null) {
211 setChild(newChild);
212 return;
213 }
214
215 YangNode curNode;
216 curNode = getChild();
217
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530218 /*
219 * Get the predecessor child of new child
220 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530221 while (curNode.getNextSibling() != null) {
Vinod Kumar S38046502016-03-23 15:30:27 +0530222
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530223 curNode = curNode.getNextSibling();
224 }
225
226 /* If the new node needs to be the last child */
227 if (curNode.getNextSibling() == null) {
228 curNode.setNextSibling(newChild);
229 newChild.setPreviousSibling(curNode);
Vinod Kumar S427d2932016-04-20 13:02:58 +0530230 }
231 }
232
233 /**
234 * Clone the current node contents and create a new node.
235 *
236 * @return cloned node
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530237 * @throws CloneNotSupportedException clone is not supported by the referred
238 * node
Vinod Kumar S427d2932016-04-20 13:02:58 +0530239 */
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530240 @Override
Vinod Kumar S427d2932016-04-20 13:02:58 +0530241 public YangNode clone()
242 throws CloneNotSupportedException {
243 YangNode clonedNode = (YangNode) super.clone();
244 clonedNode.setParent(null);
245 clonedNode.setChild(null);
246 clonedNode.setNextSibling(null);
247 clonedNode.setPreviousSibling(null);
248 return clonedNode;
249 }
250
251 /**
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530252 * Clone the subtree from the specified source node to the mentioned target
253 * node. The source and target root node cloning is carried out by the
254 * caller.
Vinod Kumar S427d2932016-04-20 13:02:58 +0530255 *
256 * @param srcRootNode source node for sub tree cloning
257 * @param dstRootNode destination node where the sub tree needs to be cloned
258 * @throws DataModelException data model error
259 */
260 public static void cloneSubTree(YangNode srcRootNode, YangNode dstRootNode)
261 throws DataModelException {
262
263 YangNode nextNodeToClone = srcRootNode;
264 TraversalType curTraversal;
265
Vinod Kumar S427d2932016-04-20 13:02:58 +0530266 YangNode clonedTreeCurNode = dstRootNode;
267 YangNode newNode = null;
268
269 nextNodeToClone = nextNodeToClone.getChild();
270 if (nextNodeToClone == null) {
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530271 return;
Vinod Kumar S427d2932016-04-20 13:02:58 +0530272 } else {
273 /**
274 * Root level cloning is taken care in the caller.
275 */
276 curTraversal = CHILD;
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530277 }
278
Vinod Kumar S427d2932016-04-20 13:02:58 +0530279 /**
280 * Caller ensures the cloning of the root nodes
Vinod Kumar S38046502016-03-23 15:30:27 +0530281 */
Vinod Kumar S427d2932016-04-20 13:02:58 +0530282 try {
283 while (nextNodeToClone != srcRootNode) {
284 if (nextNodeToClone == null) {
285 throw new DataModelException("Internal error: Cloning failed, source tree null pointer reached");
286 }
janani b4e53f9b2016-04-26 18:49:20 +0530287 if (curTraversal != PARENT) {
Vinod Kumar S427d2932016-04-20 13:02:58 +0530288 newNode = nextNodeToClone.clone();
janani b4e53f9b2016-04-26 18:49:20 +0530289 detectCollisionWhileCloning(clonedTreeCurNode, newNode, curTraversal);
290 }
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530291
janani b4e53f9b2016-04-26 18:49:20 +0530292 if (curTraversal == CHILD) {
Vinod Kumar S427d2932016-04-20 13:02:58 +0530293
294 /**
295 * add the new node to the cloned tree.
296 */
297 clonedTreeCurNode.addChild(newNode);
298
299 /**
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530300 * update the cloned tree's traversal current node as the
301 * new node.
Vinod Kumar S427d2932016-04-20 13:02:58 +0530302 */
303 clonedTreeCurNode = newNode;
304 } else if (curTraversal == SIBILING) {
Vinod Kumar S427d2932016-04-20 13:02:58 +0530305
306 clonedTreeCurNode.addNextSibling(newNode);
307 clonedTreeCurNode = newNode;
308 } else if (curTraversal == PARENT) {
309 clonedTreeCurNode = clonedTreeCurNode.getParent();
310 }
311
312 if (curTraversal != PARENT && nextNodeToClone.getChild() != null) {
313 curTraversal = CHILD;
314
315 /**
316 * update the traversal's current node.
317 */
318 nextNodeToClone = nextNodeToClone.getChild();
319
320 } else if (nextNodeToClone.getNextSibling() != null) {
321
322 curTraversal = SIBILING;
323
324 nextNodeToClone = nextNodeToClone.getNextSibling();
325 } else {
326 curTraversal = PARENT;
327 nextNodeToClone = nextNodeToClone.getParent();
328 }
329 }
330 } catch (CloneNotSupportedException e) {
331 throw new DataModelException("Failed to clone the tree");
332 }
333
334 }
335
336 /**
janani b4e53f9b2016-04-26 18:49:20 +0530337 * Detects collision when the grouping is deep copied to the uses's parent.
338 *
339 * @param currentNode parent/previous sibling node for the new node
340 * @param newNode node which has to be added
341 * @param addAs traversal type of the node
342 * @throws DataModelException data model error
343 */
344 private static void detectCollisionWhileCloning(YangNode currentNode, YangNode newNode, TraversalType addAs)
345 throws DataModelException {
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530346 if (!(currentNode instanceof CollisionDetector)
347 || !(newNode instanceof Parsable)) {
janani b4e53f9b2016-04-26 18:49:20 +0530348 throw new DataModelException("Node in data model tree does not support collision detection");
349 }
350
351 CollisionDetector collisionDetector = (CollisionDetector) currentNode;
352 Parsable parsable = (Parsable) newNode;
353 if (addAs == TraversalType.CHILD) {
354 collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
355 } else if (addAs == TraversalType.SIBILING) {
356 currentNode = currentNode.getParent();
357 if (!(currentNode instanceof CollisionDetector)) {
358 throw new DataModelException("Node in data model tree does not support collision detection");
359 }
360 collisionDetector = (CollisionDetector) currentNode;
361 collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
362 } else {
363 throw new DataModelException("Errored tree cloning");
364 }
365
366 }
367
368 /**
Vinod Kumar S427d2932016-04-20 13:02:58 +0530369 * Add a new next sibling.
370 *
371 * @param newSibling new sibling to be added
372 * @throws DataModelException data model error
373 */
374 private void addNextSibling(YangNode newSibling)
375 throws DataModelException {
376
377 if (newSibling.getNodeType() == null) {
378 throw new DataModelException("Cloned abstract node cannot be inserted into a tree");
379 }
380
381 if (newSibling.getParent() == null) {
382 /**
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530383 * Since the siblings needs to have a common parent, set the parent
384 * as the current node's parent
Vinod Kumar S427d2932016-04-20 13:02:58 +0530385 */
Vinod Kumar Se4b9b0c2016-04-30 21:09:15 +0530386 newSibling.setParent(getParent());
Vinod Kumar S427d2932016-04-20 13:02:58 +0530387
388 } else {
389 throw new DataModelException("Node is already part of a tree, and cannot be added as a sibling");
390 }
391
392 if (newSibling.getPreviousSibling() == null) {
393 newSibling.setPreviousSibling(this);
394 setNextSibling(newSibling);
395 } else {
396 throw new DataModelException("New sibling to be added is not atomic, it already has a previous sibling");
397 }
398
399 if (newSibling.getChild() != null) {
400 throw new DataModelException("Sibling to be added is not atomic, it already has a child");
401 }
402
403 if (newSibling.getNextSibling() != null) {
404 throw new DataModelException("Sibling to be added is not atomic, it already has a next sibling");
405 }
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530406 }
Vinod Kumar S8c4e6492016-02-05 20:21:19 +0530407}