blob: de65bb45bf4f32e42ce2c90ab791efad5130547b [file] [log] [blame]
Gaurav Agrawald9d6cc82016-03-29 02:17:23 +05301/*
2 * Copyright 2016 Open Networking Laboratory
3 *
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 */
16
17package org.onosproject.yangutils.datamodel;
18
19import java.util.Stack;
20import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
21
22/**
23 * Resolution object which will be resolved by linker.
24 */
25public class YangResolutionInfo<T> {
26
27 // Prefix associated with the linking.
28 private String prefix;
29
30 // Parsable node for which resolution is to be performed.
31 private T entityToResolve;
32
33 // Holder of the YANG construct for which resolution has to be carried out.
34 private YangNode holderOfEntityToResolve;
35
36 // Error Line number.
37 private int lineNumber;
38
39 // Error character position.
40 private int charPosition;
41
42 // Status of resolution.
43 private boolean isResolved;
44
45 /*
46 * Stack for type/uses is maintained for hierarchical references, this
47 * is used during resolution.
48 */
49 private Stack<T> partialResolvedStack;
50
51 // Flag to indicate whether more references are detected.
52 private boolean isMoreReferenceDetected;
53
54 // Module/Sub-module prefix.
55 private String resolutionInfoRootNodePrefix;
56
57 /**
58 * Create a resolution information object.
59 */
60 private YangResolutionInfo() {
61
62 }
63
64 /**
65 * Creates a resolution information object with all the inputs.
66 *
67 * @param dataNode current parsable data node
68 * @param resolutionType type of resolution whether grouping/typedef
69 * @param holderNode parent YANG node
70 * @param prefix imported module prefix
71 * @param lineNumber error line number
72 * @param charPositionInLine error character position in line
73 */
74 public YangResolutionInfo(T dataNode, ResolutionType resolutionType,
75 YangNode holderNode, String prefix, int lineNumber,
76 int charPositionInLine) {
77 this.setHolderOfEntityToResolve(holderNode);
78 this.setEntityToResolve(dataNode);
79 this.setPrefix(prefix);
80 this.setLineNumber(lineNumber);
81 this.setCharPosition(charPositionInLine);
82 setPartialResolvedStack(new Stack<T>());
83 }
84
85 /**
86 * Creates a resolution information object with all the inputs except prefix.
87 *
88 * @param dataNode current parsable data node
89 * @param resolutionType type of resolution whether grouping/typedef
90 * @param holderNode parent YANG node
91 * @param lineNumber error line number
92 * @param charPositionInLine error character position in line
93 */
94 public YangResolutionInfo(T dataNode, ResolutionType resolutionType,
95 YangNode holderNode, int lineNumber,
96 int charPositionInLine) {
97 this.setHolderOfEntityToResolve(holderNode);
98 this.setEntityToResolve(dataNode);
99 this.setLineNumber(lineNumber);
100 this.setCharPosition(charPositionInLine);
101 }
102
103 /**
104 * Resolve linking with all the ancestors node for a resolution info.
105 *
106 * @param resolutionInfoNodePrefix module/sub-module prefix
107 * @throws DataModelException DataModelException a violation of data model rules
108 */
109 public void resolveLinkingForResolutionInfo(String resolutionInfoNodePrefix) throws DataModelException {
110
111 this.resolutionInfoRootNodePrefix = resolutionInfoNodePrefix;
112
113 // Current node to resolve, it can be a YANG type or YANG uses.
114 T entityToResolve = getEntityToResolve();
115
116 // Check if linking is already done
117 if (entityToResolve instanceof Resolvable) {
118 Resolvable resolvable = (Resolvable) entityToResolve;
119 if (resolvable.getResolvableStatus() == ResolvableStatus.RESOLVED ||
120 resolvable.getResolvableStatus() == ResolvableStatus.PARTIALLY_RESOLVED) {
121 return;
122 }
123 } else {
124 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
125 }
126
127 // Push the initial YANG type to the stack.
128 getPartialResolvedStack().push(entityToResolve);
129
130 // Get holder of entity to resolve
131 YangNode curNode = getHolderOfEntityToResolve();
132
133 resolveLinkingWithAncestors(curNode);
134 }
135
136 /**
137 * Resolves linking with ancestors.
138 *
139 * @param curNode current node for which ancestors to be checked
140 * @throws DataModelException a violation of data model rules
141 */
142 private void resolveLinkingWithAncestors(YangNode curNode) throws DataModelException {
143
144 while (curNode != null) {
145 YangNode node = curNode.getChild();
146 if (resolveLinkingForNodesChildAndSibling(node, curNode)) {
147 return;
148 }
149 curNode = curNode.getParent();
150 }
151
152 // If curNode is null, it indicates an error condition in YANG file.
153 DataModelException dataModelException = new DataModelException("YANG file error: Unable to find base " +
154 "typedef/grouping for given type/uses");
155 dataModelException.setLine(getLineNumber());
156 dataModelException.setCharPosition(getCharPosition());
157 throw dataModelException;
158 }
159
160 /**
161 * Resolves linking for a node child and siblings.
162 *
163 * @param node current node
164 * @param parentNode parent node of current node
165 * @return flag to indicate whether resolution is done
166 * @throws DataModelException
167 */
168 private boolean resolveLinkingForNodesChildAndSibling(YangNode node, YangNode parentNode)
169 throws DataModelException {
170 while ((node != null)) {
171 isMoreReferenceDetected = false;
172 // Check if node is of type, typedef or grouping
173 if (isNodeOfResolveType(node)) {
174 if (resolveLinkingForNode(node, parentNode)) {
175 return true;
176 }
177 }
178 if (isMoreReferenceDetected) {
179 /*
180 * If more reference are present, tree traversal must start
181 * from first child again, to check the availability of
182 * typedef/grouping.
183 */
184 node = parentNode.getChild();
185 } else {
186 node = node.getNextSibling();
187 }
188 }
189 return false;
190 }
191
192 /**
193 * Resolves linking for a node.
194 *
195 * @param node current node
196 * @param parentNode parent node of current node
197 * @return flag to indicate whether resolution is done
198 * @throws DataModelException a violation of data model rules
199 */
200 private boolean resolveLinkingForNode(YangNode node, YangNode parentNode) throws
201 DataModelException {
202 /*
203 * Check if name of node name matches with the entity name
204 * under resolution.
205 */
206 if (isNodeNameSameAsResolutionInfoName(node)) {
207 // Add reference of entity to the node under resolution.
208 addReferredEntityLink(node);
209 // Check if referred entity has further reference to uses/type.
210 if (!(isMoreReferencePresent(node))) {
211 // Resolve all the entities in stack.
212 resolveStackAndAddToStack(node);
213 return true;
214 } else {
215 // Add referred type/uses to the stack.
216 addToPartialResolvedStack(node);
217 /*
218 * Check whether referred type is resolved, partially resolved
219 * or unresolved.
220 */
221 if (isReferenceFullyResolved()) {
222 // Resolve the stack which is complete.
223 resolveCompleteStack();
224 return true;
225 } else if (isReferencePartiallyResolved()) {
226 /*
227 * Update the resolution type to partially resolved for all
228 * type/uses in stack
229 */
230 updateResolutionTypeToPartial();
231 return true;
232 } else {
233 /*
234 * Check if prefix is present to find that the derived
235 * reference is for intra file or inter file, if it's
236 * inter-file return and stop further processing.
237 */
238 if (isExternalPrefixPresent(node)) {
239 /*
240 * Update the resolution type to partially resolved for all
241 * type/uses in stack
242 */
243 updateResolutionTypeToPartial();
244 return true;
245 } else {
246 /*
247 * If prefix is not present it indicates intra-file
248 * dependency in this case set the node back to first
249 * child, as referred entity may appear in any order
250 * and continue with the resolution.
251 */
252 isMoreReferenceDetected = true;
253 return false;
254 }
255 }
256 }
257 }
258 return false;
259 }
260
261 /**
262 * Update resolution type to partial for all type/uses in stack.
263 *
264 * @throws DataModelException a violation of data model rules
265 */
266 private void updateResolutionTypeToPartial() throws DataModelException {
267 // For all entries in stack calls for the resolution in type/uses.
268 for (T entity:getPartialResolvedStack()) {
269 if (!(entity instanceof Resolvable)) {
270 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
271 }
272 if (((Resolvable) entity).getResolvableStatus() == ResolvableStatus.UNRESOLVED) {
273 // Set the resolution status in inside the type/uses.
274 ((Resolvable) entity).setResolvableStatus(ResolvableStatus.PARTIALLY_RESOLVED);
275 }
276 }
277 }
278
279 /**
280 * Add referred type/uses to the stack and resolve the stack.
281 *
282 * @param node typedef/grouping node
283 * @throws DataModelException a violation of data model rules
284 */
285 private void resolveStackAndAddToStack(YangNode node) throws DataModelException {
286 if (getEntityToResolve() instanceof YangType) {
287 // Add to the stack only for YANG typedef.
288 getPartialResolvedStack().push((T) ((YangTypeDef) node).getDataType());
289 }
290 // Don't add to stack in case of YANG grouping.
291
292 // Resolve the complete stack.
293 resolveCompleteStack();
294 }
295
296 /**
297 * Check if the referred type/uses is partially resolved.
298 *
299 * @return true if reference is partially resolved, otherwise false
300 */
301 private boolean isReferencePartiallyResolved() {
302 if (getPartialResolvedStack().peek() instanceof YangType) {
303 /*
304 * Checks if type is partially resolved.
305 */
306 if (((YangType) getPartialResolvedStack().peek()).getResolvableStatus() ==
307 ResolvableStatus.PARTIALLY_RESOLVED) {
308 return true;
309 }
310 } else if (getPartialResolvedStack().peek() instanceof YangUses) {
311 if (((YangUses) getPartialResolvedStack().peek()).getResolvableStatus() ==
312 ResolvableStatus.PARTIALLY_RESOLVED) {
313 return true;
314 }
315 }
316 return false;
317 }
318
319 /**
320 * Check if the referred type/uses is resolved.
321 *
322 * @return true if reference is resolved, otherwise false
323 */
324 private boolean isReferenceFullyResolved() {
325 if (getPartialResolvedStack().peek() instanceof YangType) {
326 /*
327 * Checks if type is partially resolved.
328 */
329 if (((YangType) getPartialResolvedStack().peek()).getResolvableStatus() ==
330 ResolvableStatus.RESOLVED) {
331 return true;
332 }
333 } else if (getPartialResolvedStack().peek() instanceof YangUses) {
334 if (((YangUses) getPartialResolvedStack().peek()).getResolvableStatus() ==
335 ResolvableStatus.RESOLVED) {
336 return true;
337 }
338 }
339 return false;
340 }
341
342 /**
343 * Check if node is of resolve type i.e. of type typedef or grouping.
344 *
345 * @param node typedef/grouping node
346 * @return true if node is of resolve type otherwise false
347 * @throws DataModelException a violation of data model rules
348 */
349 private boolean isNodeOfResolveType(YangNode node) throws DataModelException {
350 if (getPartialResolvedStack().peek() instanceof YangType && entityToResolve instanceof YangType) {
351 if (node instanceof YangTypeDef) {
352 return true;
353 }
354 } else if (getPartialResolvedStack().peek() instanceof YangUses && entityToResolve instanceof YangUses) {
355 if (node instanceof YangGrouping) {
356 return true;
357 }
358 } else {
359 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
360 }
361 return false;
362 }
363
364
365 /**
366 * Check if node name is same as name in resolution info, i.e. name of
367 * typedef/grouping is same as name of type/uses.
368 *
369 * @param node typedef/grouping node
370 * @return true if node name is same as name in resolution info, otherwise
371 * false
372 * @throws DataModelException a violation of data model rules
373 */
374 private boolean isNodeNameSameAsResolutionInfoName(YangNode node) throws DataModelException {
375 if (getPartialResolvedStack().peek() instanceof YangType) {
376 if (node.getName().equals(((YangType<?>) getPartialResolvedStack().peek()).getDataTypeName())) {
377 return true;
378 }
379 } else if (getPartialResolvedStack().peek() instanceof YangUses) {
380 if (node.getName().equals(((YangUses) getPartialResolvedStack().peek()).getName())) {
381 return true;
382 }
383 } else {
384 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
385 }
386 return false;
387 }
388
389 /**
390 * Add reference of grouping/typedef in uses/type.
391 *
392 * @param node grouping/typedef node
393 * @throws DataModelException a violation of data model rules
394 */
395 private void addReferredEntityLink(YangNode node) throws DataModelException {
396 if (getPartialResolvedStack().peek() instanceof YangType) {
397 YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>) ((YangType<?>) getPartialResolvedStack().peek())
398 .getDataTypeExtendedInfo();
399 derivedInfo.setReferredTypeDef((YangTypeDef) node);
400 } else if (getPartialResolvedStack().peek() instanceof YangUses) {
401 ((YangUses) getPartialResolvedStack().peek()).setRefGroup((YangGrouping) node);
402 } else {
403 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
404 }
405 }
406
407 /**
408 * Checks if typedef/grouping has further reference to type/typedef.
409 *
410 * @param node grouping/typedef node
411 * @return true if referred entity is resolved, otherwise false
412 * @throws DataModelException a violation of data model rules
413 */
414 private boolean isMoreReferencePresent(YangNode node) throws DataModelException {
415 if (getEntityToResolve() instanceof YangType) {
416 /*
417 * Checks if typedef type is built-in type
418 */
419 if ((((YangTypeDef) node).getDataType().getDataType() != YangDataTypes.DERIVED)) {
420 return false;
421 }
422 } else if (getEntityToResolve() instanceof YangUses) {
423 /*
424 * Search if the grouping has any uses child, if so return false,
425 * else return true.
426 */
427 if (getUsesInGrouping(node) == null) {
428 return false;
429 }
430 } else {
431 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
432 }
433 return true;
434 }
435
436 /**
437 * Return if there is any uses in grouping.
438 *
439 * @param node grouping/typedef node
440 * @return if there is any uses in grouping, otherwise return null
441 */
442 private YangUses getUsesInGrouping(YangNode node) {
443 YangNode curNode = ((YangGrouping) node).getChild();
444 while (curNode != null) {
445 if (curNode instanceof YangUses) {
446 break;
447 }
448 curNode = curNode.getNextSibling();
449 }
450 return (YangUses) curNode;
451 }
452
453 /**
454 * Resolve the complete stack.
455 *
456 * @throws DataModelException a violation of data model rules
457 */
458 private void resolveCompleteStack() throws DataModelException {
459 // For all entries in stack calls for the resolution in type/uses.
460 for (T entity:getPartialResolvedStack()) {
461 if (!(entity instanceof Resolvable)) {
462 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
463 }
464 ((Resolvable) entity).resolve();
465 // Set the resolution status in inside the type/uses.
466 ((Resolvable) entity).setResolvableStatus(ResolvableStatus.RESOLVED);
467 }
468 /*
469 * Set the resolution status in resolution info present in resolution
470 * list.
471 */
472 setIsResolved(true);
473 }
474
475 /**
476 * Add to partial resolved stack.
477 *
478 * @param node grouping/typedef node
479 * @throws DataModelException a violation of data model rules
480 */
481 private void addToPartialResolvedStack(YangNode node) throws DataModelException {
482 if (getPartialResolvedStack().peek() instanceof YangType) {
483 // Add to the stack only for YANG typedef.
484 getPartialResolvedStack().push((T) ((YangTypeDef) node).getDataType());
485 } else if (getPartialResolvedStack().peek() instanceof YangUses) {
486 getPartialResolvedStack().push((T) getUsesInGrouping(node));
487 } else {
488 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
489 }
490 }
491
492 /**
493 * Check if prefix is associated with type/uses.
494 *
495 * @param node typedef/grouping node
496 * @return true if prefix is present, otherwise false
497 * @throws DataModelException a violation of data model rules
498 */
499 private boolean isExternalPrefixPresent(YangNode node) throws DataModelException {
500 if (getEntityToResolve() instanceof YangType) {
501 if (((YangTypeDef) node).getDataType().getPrefix() != null &&
502 (!((YangTypeDef) node).getDataType().getPrefix().equals(resolutionInfoRootNodePrefix))) {
503 return true;
504 }
505 } else if (getEntityToResolve() instanceof YangUses) {
506 if (getUsesInGrouping(node).getPrefix() != null) {
507 return true;
508 }
509 } else {
510 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
511 }
512 return false;
513 }
514
515 /**
516 * Returns prefix of imported module.
517 *
518 * @return prefix of imported module
519 */
520 public String getPrefix() {
521 return prefix;
522 }
523
524 /**
525 * Set prefix of imported module.
526 *
527 * @param prefix of imported module
528 */
529 public void setPrefix(String prefix) {
530 this.prefix = prefix;
531 }
532
533 /**
534 * Returns parsable entity which is to be resolved.
535 *
536 * @return parsable entity which is to be resolved
537 */
538 public T getEntityToResolve() {
539 return entityToResolve;
540 }
541
542 /**
543 * Set parsable entity to be resolved.
544 *
545 * @param entityToResolve YANG entity to be resolved
546 */
547 public void setEntityToResolve(T entityToResolve) {
548 this.entityToResolve = entityToResolve;
549 }
550
551 /**
552 * Returns parent YANG node holder for the entity to be resolved.
553 *
554 * @return parent YANG node holder
555 */
556 public YangNode getHolderOfEntityToResolve() {
557 return holderOfEntityToResolve;
558 }
559
560 /**
561 * Set parent YANG node holder for the entity to be resolved.
562 *
563 * @param holderOfEntityToResolve parent YANG node holder
564 */
565 public void setHolderOfEntityToResolve(YangNode holderOfEntityToResolve) {
566 this.holderOfEntityToResolve = holderOfEntityToResolve;
567 }
568
569 /**
570 * Returns error position.
571 *
572 * @return error position
573 */
574 public int getCharPosition() {
575 return charPosition;
576 }
577
578 /**
579 * Set error position.
580 *
581 * @param charPosition position of error
582 */
583 public void setCharPosition(int charPosition) {
584 this.charPosition = charPosition;
585 }
586
587 /**
588 * Returns error character position in line.
589 *
590 * @return error character position in line
591 */
592 public int getLineNumber() {
593 return lineNumber;
594 }
595
596 /**
597 * Set error character position in line.
598 *
599 * @param lineNumber error character position in line
600 */
601 public void setLineNumber(int lineNumber) {
602 this.lineNumber = lineNumber;
603 }
604
605 /**
606 * Returns status of resolution.
607 *
608 * @return resolution status
609 */
610 public boolean isResolved() {
611 return isResolved;
612 }
613
614 /**
615 * Set status of resolution.
616 *
617 * @param isResolved resolution status
618 */
619 public void setIsResolved(boolean isResolved) {
620 this.isResolved = isResolved;
621 }
622
623 /**
624 * Returns stack of YANG type with partially resolved YANG construct hierarchy.
625 *
626 * @return partial resolved YANG construct stack
627 */
628 public Stack<T> getPartialResolvedStack() {
629 return partialResolvedStack;
630 }
631
632 /**
633 * Set stack of YANG type with partially resolved YANG construct hierarchy.
634 *
635 * @param partialResolvedStack partial resolved YANG construct stack
636 */
637 public void setPartialResolvedStack(Stack<T> partialResolvedStack) {
638 this.partialResolvedStack = partialResolvedStack;
639 }
640}