blob: 83b11c4d1309543d5ae7413bdaaf8e65b35b0988 [file] [log] [blame]
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +05301/*
2 * Copyright 2016-present 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.linker.impl;
18
19import java.util.Stack;
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +053020
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +053021import org.onosproject.yangutils.datamodel.LocationInfo;
22import org.onosproject.yangutils.datamodel.YangDataTypes;
23import org.onosproject.yangutils.datamodel.YangDerivedInfo;
24import org.onosproject.yangutils.datamodel.YangGrouping;
25import org.onosproject.yangutils.datamodel.YangImport;
26import org.onosproject.yangutils.datamodel.YangInclude;
27import org.onosproject.yangutils.datamodel.YangNode;
28import org.onosproject.yangutils.datamodel.YangType;
29import org.onosproject.yangutils.datamodel.YangTypeDef;
30import org.onosproject.yangutils.datamodel.YangUses;
31import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +053032import org.onosproject.yangutils.linker.Resolvable;
33import org.onosproject.yangutils.linker.ResolvableStatus;
34import org.onosproject.yangutils.linker.YangLinkingPhase;
35import org.onosproject.yangutils.linker.YangReferenceResolver;
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +053036
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +053037import static org.onosproject.yangutils.linker.ResolvableStatus.INTER_FILE_LINKED;
38import static org.onosproject.yangutils.linker.ResolvableStatus.INTRA_FILE_RESOLVED;
39import static org.onosproject.yangutils.linker.ResolvableStatus.LINKED;
40import static org.onosproject.yangutils.linker.ResolvableStatus.RESOLVED;
41import static org.onosproject.yangutils.linker.ResolvableStatus.UNRESOLVED;
42import static org.onosproject.yangutils.linker.YangLinkingPhase.INTER_FILE;
43import static org.onosproject.yangutils.linker.YangLinkingPhase.INTRA_FILE;
Vidyashree Rama210c01d2016-05-20 16:29:25 +053044import static org.onosproject.yangutils.utils.UtilConstants.TYPEDEF_LINKER_ERROR;
45import static org.onosproject.yangutils.utils.UtilConstants.GROUPING_LINKER_ERROR;
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +053046
47/**
48 * Represents resolution object which will be resolved by linker.
49 *
50 * @param <T> type of resolution entity uses / type
51 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +053052public class YangResolutionInfo<T>
53 implements LocationInfo {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +053054
55 /**
56 * Information about the entity that needs to be resolved.
57 */
58 private YangEntityToResolveInfo<T> entityToResolveInfo;
59
60 /**
61 * Error line number.
62 */
63 private int lineNumber;
64
65 /**
66 * Error character position in number.
67 */
68 private int charPosition;
69
70 /**
71 * Current module/sub-module reference, will be used in inter-file/
72 * inter-jar scenario to get the import/include list.
73 */
74 private YangReferenceResolver curReferenceResolver;
75
76 /**
77 * Stack for type/uses is maintained for hierarchical references, this is
78 * used during resolution.
79 */
80 private Stack<YangEntityToResolveInfo<T>> partialResolvedStack;
81
82 /**
83 * It is private to ensure the overloaded method be invoked to create an
84 * object.
85 */
86 @SuppressWarnings("unused")
87 private YangResolutionInfo() {
88
89 }
90
91 /**
92 * Creates a resolution information object with all the inputs.
93 *
94 * @param dataNode current parsable data node
95 * @param holderNode parent YANG node
96 * @param lineNumber error line number
97 * @param charPositionInLine error character position in line
98 */
99 public YangResolutionInfo(T dataNode, YangNode holderNode, int lineNumber, int charPositionInLine) {
100 setEntityToResolveInfo(new YangEntityToResolveInfo<>());
101 getEntityToResolveInfo().setEntityToResolve(dataNode);
102 getEntityToResolveInfo().setHolderOfEntityToResolve(holderNode);
103 this.setLineNumber(lineNumber);
104 this.setCharPosition(charPositionInLine);
105 setPartialResolvedStack(new Stack<>());
106 }
107
108 /**
109 * Resolves linking with all the ancestors node for a resolution info.
110 *
111 * @param dataModelRootNode module/sub-module node
112 * @throws DataModelException DataModelException a violation of data model
113 * rules
114 */
115 public void resolveLinkingForResolutionInfo(YangReferenceResolver dataModelRootNode)
116 throws DataModelException {
117
118 setCurReferenceResolver(dataModelRootNode);
119
120 // Current node to resolve, it can be a YANG type or YANG uses.
121 T entityToResolve = getEntityToResolveInfo().getEntityToResolve();
122
123 // Check if linking is already done
124 if (entityToResolve instanceof Resolvable) {
125 Resolvable resolvable = (Resolvable) entityToResolve;
126 if (resolvable.getResolvableStatus() == RESOLVED) {
127 /**
128 * entity is already resolved, so nothing to do
129 */
130 return;
131 }
132 } else {
133 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
134 }
135
136 // Push the initial entity to resolve in stack.
137 addInPartialResolvedStack(getEntityToResolveInfo());
138
139 linkAndResolvePartialResolvedStack();
140 }
141
142 /**
143 * Resolves linking with ancestors.
144 *
145 * @throws DataModelException a violation of data model rules
146 */
147 private void linkAndResolvePartialResolvedStack()
148 throws DataModelException {
149
150 while (getPartialResolvedStack().size() != 0) {
151
152 // Current node to resolve, it can be a YANG type or YANG uses.
153 T entityToResolve = getCurrentEntityToResolveFromStack();
154 // Check if linking is already done
155 if (entityToResolve instanceof Resolvable) {
156
157 Resolvable resolvable = (Resolvable) entityToResolve;
158 switch (resolvable.getResolvableStatus()) {
159 case RESOLVED: {
160 /*
161 * If the entity is already resolved in the stack, then
162 * pop it and continue with the remaining stack elements
163 * to resolve
164 */
165 getPartialResolvedStack().pop();
166 break;
167 }
168
169 case LINKED: {
170 /*
171 * If the top of the stack is already linked then
172 * resolve the references and pop the entity and
173 * continue with remaining stack elements to resolve.
174 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530175 resolveTopOfStack(INTRA_FILE);
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530176 getPartialResolvedStack().pop();
177 break;
178 }
179
180 case INTRA_FILE_RESOLVED: {
181 /*
182 * Pop the top of the stack.
183 */
184 getPartialResolvedStack().pop();
185 break;
186 }
187
188 case UNRESOLVED: {
189 linkTopOfStackReferenceUpdateStack();
190
191 if (resolvable.getResolvableStatus() == UNRESOLVED) {
192 // If current entity is still not resolved, then linking/resolution has failed.
Vidyashree Rama210c01d2016-05-20 16:29:25 +0530193 String errorInfo;
194 if (resolvable instanceof YangType) {
195 errorInfo = TYPEDEF_LINKER_ERROR;
196 } else {
197 errorInfo = GROUPING_LINKER_ERROR;
198 }
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530199 DataModelException dataModelException =
Vidyashree Rama210c01d2016-05-20 16:29:25 +0530200 new DataModelException(errorInfo);
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530201 dataModelException.setLine(getLineNumber());
202 dataModelException.setCharPosition(getCharPosition());
203 throw dataModelException;
204 }
205 break;
206 }
207 default: {
208 throw new DataModelException("Data Model Exception: Unsupported, linker state");
209 }
210
211 }
212
213 } else {
214 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
215 }
216
217 }
218
219 }
220
221 /**
222 * Resolves the current entity in the stack.
223 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530224 private void resolveTopOfStack(YangLinkingPhase linkingPhase)
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530225 throws DataModelException {
226 ((Resolvable) getCurrentEntityToResolveFromStack()).resolve();
227 if (((Resolvable) getCurrentEntityToResolveFromStack()).getResolvableStatus()
228 != INTRA_FILE_RESOLVED) {
229 // Sets the resolution status in inside the type/uses.
230 ((Resolvable) getCurrentEntityToResolveFromStack()).setResolvableStatus(RESOLVED);
231 }
232 }
233
234 /**
235 * Resolves linking for a node child and siblings.
236 *
237 * @throws DataModelException data model error
238 */
239 private void linkTopOfStackReferenceUpdateStack()
240 throws DataModelException {
241
242 /*
243 * Check if self file reference is there, this will not check for the
244 * scenario when prefix is not present and type/uses is present in
245 * sub-module from include list.
246 */
247 if (!isCandidateForSelfFileReference()) {
248 ((Resolvable) getCurrentEntityToResolveFromStack()).setResolvableStatus(INTRA_FILE_RESOLVED);
249 return;
250 }
251
252 /**
253 * Try to resolve the top of the stack and update partial resolved stack
254 * if there is recursive references
255 */
256 YangNode potentialAncestorWithReferredNode = getPartialResolvedStack().peek()
257 .getHolderOfEntityToResolve();
258
259 /**
260 * Traverse up in the ancestor tree to check if the referred node is
261 * defined
262 */
263 while (potentialAncestorWithReferredNode != null) {
264
265 /**
266 * Check for the referred node defined in a ancestor scope
267 */
268 YangNode potentialReferredNode = potentialAncestorWithReferredNode.getChild();
269 if (isReferredNodeInSiblingListProcessed(potentialReferredNode)) {
270 return;
271 }
272
273 potentialAncestorWithReferredNode = potentialAncestorWithReferredNode.getParent();
274 }
275
276 /*
277 * In case prefix is not present it's a candidate for inter-file
278 * resolution via include list.
279 */
280 if (getRefPrefix() == null) {
281 ((Resolvable) getCurrentEntityToResolveFromStack()).setResolvableStatus(INTRA_FILE_RESOLVED);
282 }
283 }
284
285 /**
286 * Checks if the reference in self file or in external file.
287 *
288 * @return true if self file reference, false otherwise
289 * @throws DataModelException a violation of data model rules
290 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530291 private boolean isCandidateForSelfFileReference()
292 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530293 String prefix = getRefPrefix();
294 return prefix == null || prefix.contentEquals(getCurReferenceResolver().getPrefix());
295 }
296
297 /**
298 * Checks for the referred node defined in a ancestor scope.
299 *
300 * @param potentialReferredNode potential referred node
301 * @return status of resolution and updating the partial resolved stack with
302 * the any recursive references
303 * @throws DataModelException data model errors
304 */
305 private boolean isReferredNodeInSiblingListProcessed(YangNode potentialReferredNode)
306 throws DataModelException {
307 while (potentialReferredNode != null) {
308
309 // Check if the potential referred node is the actual referred node
310 if (isReferredNode(potentialReferredNode)) {
311
312 // Adds reference link of entity to the node under resolution.
313 addReferredEntityLink(potentialReferredNode, LINKED);
314
315 /**
316 * resolve the reference and update the partial resolution stack
317 * with any further recursive references
318 */
319 addUnresolvedRecursiveReferenceToStack(potentialReferredNode);
320
321 /*
322 * return true, since the reference is linked and any recursive
323 * unresolved references is added to the stack
324 */
325 return true;
326 }
327
328 potentialReferredNode = potentialReferredNode.getNextSibling();
329 }
330 return false;
331 }
332
333 /**
334 * Checks if the potential referred node is the actual referred node.
335 *
336 * @param potentialReferredNode typedef/grouping node
337 * @return true if node is of resolve type otherwise false
338 * @throws DataModelException a violation of data model rules
339 */
340 private boolean isReferredNode(YangNode potentialReferredNode)
341 throws DataModelException {
342 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
343 if (potentialReferredNode instanceof YangTypeDef) {
344 /*
345 * Check if name of node name matches with the entity being
346 * resolved
347 */
348 return isNodeNameSameAsResolutionInfoName(potentialReferredNode);
349 }
350 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
351 if (potentialReferredNode instanceof YangGrouping) {
352 /*
353 * Check if name of node name matches with the entity being
354 * resolved
355 */
356 return isNodeNameSameAsResolutionInfoName(potentialReferredNode);
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 * Checks if node name is same as name in resolution info, i.e. name of
366 * typedef/grouping is same as name of type/uses.
367 *
368 * @param node typedef/grouping node
369 * @return true if node name is same as name in resolution info, otherwise
370 * false
371 * @throws DataModelException a violation of data model rules
372 */
373
374 private boolean isNodeNameSameAsResolutionInfoName(YangNode node)
375 throws DataModelException {
376 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
377 if (node.getName().contentEquals(
378 ((YangType<?>) getCurrentEntityToResolveFromStack())
379 .getDataTypeName())) {
380 return true;
381 }
382 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
383 if (node.getName().contentEquals(
384 ((YangUses) getCurrentEntityToResolveFromStack()).getName())) {
385 return true;
386 }
387 } else {
388 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
389 }
390 return false;
391 }
392
393 /**
394 * Adds reference of grouping/typedef in uses/type.
395 *
396 * @param referredNode grouping/typedef node being referred
397 * @param linkedStatus linked status if success.
398 * @throws DataModelException a violation of data model rules
399 */
400 private void addReferredEntityLink(YangNode referredNode, ResolvableStatus linkedStatus)
401 throws DataModelException {
402 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
403 YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>)
404 ((YangType<?>) getCurrentEntityToResolveFromStack()).getDataTypeExtendedInfo();
405 derivedInfo.setReferredTypeDef((YangTypeDef) referredNode);
406 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
407 ((YangUses) getCurrentEntityToResolveFromStack())
408 .setRefGroup((YangGrouping) referredNode);
409 } else {
410 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
411 }
412
413 // Sets the resolution status in inside the type/uses.
414 ((Resolvable) getCurrentEntityToResolveFromStack()).setResolvableStatus(linkedStatus);
415 }
416
417 /**
418 * Checks if type/grouping has further reference to typedef/ unresolved
419 * uses. Add it to the partial resolve stack and return the status of
420 * addition to stack.
421 *
422 * @param referredNode grouping/typedef node
423 * @throws DataModelException a violation of data model rules
424 */
425 private void addUnresolvedRecursiveReferenceToStack(YangNode referredNode)
426 throws DataModelException {
427 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
428 /*
429 * Checks if typedef type is derived
430 */
431 if (((YangTypeDef) referredNode).getTypeDefBaseType().getDataType()
432 == YangDataTypes.DERIVED) {
433
434 YangEntityToResolveInfo<YangType<?>> unResolvedEntityInfo = new YangEntityToResolveInfo<>();
435 unResolvedEntityInfo.setEntityToResolve(((YangTypeDef) referredNode)
436 .getTypeDefBaseType());
437 unResolvedEntityInfo.setHolderOfEntityToResolve(referredNode);
438 addInPartialResolvedStack((YangEntityToResolveInfo<T>) unResolvedEntityInfo);
439 }
440
441 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
442 /*
443 * Search if the grouping has any un resolved uses child, if so
444 * return true, else return false.
445 */
446 addUnResolvedUsesToStack(referredNode);
447 } else {
448 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
449 }
450 }
451
452 /**
453 * Returns if there is any unresolved uses in grouping.
454 *
455 * @param node grouping/typedef node
456 */
457 private void addUnResolvedUsesToStack(YangNode node) {
458
459 /**
460 * Search the grouping node's children for presence of uses node.
461 */
462 YangNode curNode = node.getChild();
463 while (curNode != null) {
464 if (curNode instanceof YangUses) {
465 YangEntityToResolveInfo<YangUses> unResolvedEntityInfo = new YangEntityToResolveInfo<>();
466 unResolvedEntityInfo.setEntityToResolve((YangUses) curNode);
467 unResolvedEntityInfo.setHolderOfEntityToResolve(node);
468 addInPartialResolvedStack((YangEntityToResolveInfo<T>) unResolvedEntityInfo);
469
470 }
471 curNode = curNode.getNextSibling();
472 }
473 }
474
475 /**
476 * Returns stack of YANG type with partially resolved YANG construct
477 * hierarchy.
478 *
479 * @return partial resolved YANG construct stack
480 */
481 private Stack<YangEntityToResolveInfo<T>> getPartialResolvedStack() {
482 return partialResolvedStack;
483 }
484
485 /**
486 * Sets stack of YANG type with partially resolved YANG construct hierarchy.
487 *
488 * @param partialResolvedStack partial resolved YANG construct stack
489 */
490 private void setPartialResolvedStack(Stack<YangEntityToResolveInfo<T>> partialResolvedStack) {
491 this.partialResolvedStack = partialResolvedStack;
492 }
493
494 /**
495 * Sets stack of YANG type with partially resolved YANG construct hierarchy.
496 *
497 * @param partialResolvedInfo partial resolved YANG construct stack
498 */
499 private void addInPartialResolvedStack(YangEntityToResolveInfo<T> partialResolvedInfo) {
500 getPartialResolvedStack().push(partialResolvedInfo);
501 }
502
503 /**
504 * Retrieves the next entity in the stack that needs to be resolved. It is
505 * assumed that the caller ensures that the stack is not empty.
506 *
507 * @return next entity in the stack that needs to be resolved
508 */
509 private T getCurrentEntityToResolveFromStack() {
510 return getPartialResolvedStack().peek().getEntityToResolve();
511 }
512
513 /**
514 * Retrieves information about the entity that needs to be resolved.
515 *
516 * @return information about the entity that needs to be resolved
517 */
518 public YangEntityToResolveInfo<T> getEntityToResolveInfo() {
519 return entityToResolveInfo;
520 }
521
522 /**
523 * Sets information about the entity that needs to be resolved.
524 *
525 * @param entityToResolveInfo information about the entity that needs to be
526 * resolved
527 */
528 private void setEntityToResolveInfo(YangEntityToResolveInfo<T> entityToResolveInfo) {
529 this.entityToResolveInfo = entityToResolveInfo;
530 }
531
532 @Override
533 public int getLineNumber() {
534 return lineNumber;
535 }
536
537 @Override
538 public int getCharPosition() {
539 return charPosition;
540 }
541
542 @Override
543 public void setLineNumber(int lineNumber) {
544 this.lineNumber = lineNumber;
545 }
546
547 @Override
548 public void setCharPosition(int charPositionInLine) {
549 this.charPosition = charPositionInLine;
550 }
551
552 /**
553 * Returns current module/sub-module reference, will be used in inter-file/
554 * inter-jar scenario to get the import/include list.
555 *
556 * @return current module/sub-module reference
557 */
558 private YangReferenceResolver getCurReferenceResolver() {
559 return curReferenceResolver;
560 }
561
562 /**
563 * Sets current module/sub-module reference, will be used in inter-file/
564 * inter-jar scenario to get the import/include list.
565 *
566 * @param curReferenceResolver current module/sub-module reference
567 */
568 private void setCurReferenceResolver(YangReferenceResolver curReferenceResolver) {
569 this.curReferenceResolver = curReferenceResolver;
570 }
571
572 /**
573 * Performs inter file linking of uses/type referring to typedef/grouping
574 * of other YANG file.
575 *
576 * @param dataModelRootNode module/sub-module node
577 * @throws DataModelException a violation in data model rule
578 */
579 public void linkInterFile(YangReferenceResolver dataModelRootNode)
580 throws DataModelException {
581
582 setCurReferenceResolver(dataModelRootNode);
583
584 // Current node to resolve, it can be a YANG type or YANG uses.
585 T entityToResolve = getEntityToResolveInfo().getEntityToResolve();
586
587 // Check if linking is already done
588 if (entityToResolve instanceof Resolvable) {
589 Resolvable resolvable = (Resolvable) entityToResolve;
590 if (resolvable.getResolvableStatus() == RESOLVED) {
591 return;
592 }
593 } else {
594 throw new DataModelException("Data Model Exception: Entity to resolved is not Resolvable");
595 }
596
597 // Push the initial entity to resolve in stack.
598 addInPartialResolvedStack(getEntityToResolveInfo());
599
600 // Inter file linking and resolution.
601 linkInterFileAndResolve();
602 }
603
604 /**
605 * Returns the referenced prefix of entity under resolution.
606 *
607 * @return referenced prefix of entity under resolution
608 * @throws DataModelException a violation in data model rule
609 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530610 private String getRefPrefix()
611 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530612 String refPrefix;
613 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
614 refPrefix = ((YangType<?>) getCurrentEntityToResolveFromStack()).getPrefix();
615 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
616 refPrefix = ((YangUses) getCurrentEntityToResolveFromStack()).getPrefix();
617 } else {
618 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
619 }
620 return refPrefix;
621 }
622
623 /**
624 * Performs inter file linking and resolution.
625 *
626 * @throws DataModelException a violation in data model rule
627 */
628 private void linkInterFileAndResolve()
629 throws DataModelException {
630
631 while (getPartialResolvedStack().size() != 0) {
632
633 // Current node to resolve, it can be a YANG type or YANG uses.
634 T entityToResolve = getCurrentEntityToResolveFromStack();
635 // Check if linking is already done
636 if (entityToResolve instanceof Resolvable) {
637
638 Resolvable resolvable = (Resolvable) entityToResolve;
639 switch (resolvable.getResolvableStatus()) {
640 case RESOLVED: {
641 /*
642 * If the entity is already resolved in the stack, then
643 * pop it and continue with the remaining stack elements
644 * to resolve
645 */
646 getPartialResolvedStack().pop();
647 break;
648 }
649
650 case INTER_FILE_LINKED: {
651 /*
652 * If the top of the stack is already linked then
653 * resolve the references and pop the entity and
654 * continue with remaining stack elements to resolve
655 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530656 resolveTopOfStack(INTER_FILE);
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530657 getPartialResolvedStack().pop();
658 break;
659 }
660
661 case INTRA_FILE_RESOLVED: {
662 /*
663 * If the top of the stack is intra file resolved
664 * then check if top of stack is linked, if not
665 * link it using import/include list and push the
666 * linked referred entity to the stack, otherwise
667 * only push it to the stack.
668 */
669 linkInterFileTopOfStackRefUpdateStack();
670 break;
671 }
672
673 default: {
674 throw new DataModelException("Data Model Exception: Unsupported, linker state");
675 }
676
677 }
678
679 } else {
680 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
681 }
682
683 }
684
685 }
686
687 /**
688 * Links the top of the stack if it's inter-file and update stack.
689 *
690 * @throws DataModelException data model error
691 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530692 private void linkInterFileTopOfStackRefUpdateStack()
693 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530694
695 /*
696 * Obtain the referred node of top of stack entity under resolution
697 */
698 T referredNode = getRefNode();
699
700 /*
701 * Check for null for scenario when it's not linked and inter-file
702 * linking is required.
703 */
704 if (referredNode == null) {
705
706 /*
707 * Check if prefix is null or not, to identify whether to search
708 * in import list or include list.
709 */
Bharat saraswalcad0e652016-05-26 23:48:38 +0530710 if (getRefPrefix() != null && !getRefPrefix().contentEquals(getCurReferenceResolver().getPrefix())) {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530711 if (resolveWithImport()) {
712 return;
713 }
714 } else {
715 if (resolveWithInclude()) {
716 return;
717 }
718 }
719 // Exception when referred typedef/grouping is not found.
720 DataModelException dataModelException = new DataModelException("YANG file error: Referred " +
721 "typedef/grouping for a given type/uses can't be found.");
722 dataModelException.setLine(getLineNumber());
723 dataModelException.setCharPosition(getCharPosition());
724 throw dataModelException;
725 } else {
726 /*
727 * If referred node is already linked, then just change the status
728 * and push to the stack.
729 */
730 ((Resolvable) getCurrentEntityToResolveFromStack()).setResolvableStatus(INTER_FILE_LINKED);
731 addUnresolvedRecursiveReferenceToStack((YangNode) referredNode);
732 }
733 }
734
735 /**
736 * Finds and resolves with include list.
737 *
738 * @return true if resolved, false otherwise
739 * @throws DataModelException a violation in data model rule
740 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530741 private boolean resolveWithInclude()
742 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530743 /*
744 * Run through all the nodes in include list and search for referred
745 * typedef/grouping at the root level.
746 */
747 for (YangInclude yangInclude : getCurReferenceResolver().getIncludeList()) {
748 YangNode linkedNode = null;
749 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
750 linkedNode = findRefTypedef(yangInclude.getIncludedNode());
751 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
752 linkedNode = findRefGrouping(yangInclude.getIncludedNode());
753 }
754 if (linkedNode != null) {
755 // Add the link to external entity.
756 addReferredEntityLink(linkedNode, INTER_FILE_LINKED);
757 /*
758 * Update the current reference resolver to external
759 * module/sub-module containing the referred typedef/grouping.
760 */
761 setCurReferenceResolver((YangReferenceResolver) yangInclude.getIncludedNode());
762 // Add the type/uses of referred typedef/grouping to the stack.
763 addUnresolvedRecursiveReferenceToStack(linkedNode);
764 return true;
765 }
766 }
767 // If referred node can't be found return false.
768 return false;
769 }
770
771 /**
772 * Finds and resolves with import list.
773 *
774 * @return true if resolved, false otherwise
775 * @throws DataModelException a violation in data model rule
776 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530777 private boolean resolveWithImport()
778 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530779 /*
780 * Run through import list to find the referred typedef/grouping.
781 */
782 for (YangImport yangImport : getCurReferenceResolver().getImportList()) {
783 /*
784 * Match the prefix attached to entity under resolution with the
785 * imported/included module/sub-module's prefix. If found, search
786 * for the referred typedef/grouping at the root level.
787 */
788 if (yangImport.getPrefixId().contentEquals(getRefPrefix())) {
789 YangNode linkedNode = null;
790 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
791 linkedNode = findRefTypedef(yangImport.getImportedNode());
792 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
793 linkedNode = findRefGrouping(yangImport.getImportedNode());
794 }
795 if (linkedNode != null) {
796 // Add the link to external entity.
797 addReferredEntityLink(linkedNode, INTER_FILE_LINKED);
798 /*
799 * Update the current reference resolver to external
800 * module/sub-module containing the referred typedef/grouping.
801 */
802 setCurReferenceResolver((YangReferenceResolver) yangImport.getImportedNode());
803 // Add the type/uses of referred typedef/grouping to the stack.
804 addUnresolvedRecursiveReferenceToStack(linkedNode);
805 return true;
806 }
807 /*
808 * If referred node can't be found at root level break for loop,
809 * and return false.
810 */
811 break;
812 }
813 }
814 // If referred node can't be found return false.
815 return false;
816 }
817
818 /**
819 * Returns referred typedef/grouping node.
820 *
821 * @return referred typedef/grouping node
822 * @throws DataModelException a violation in data model rule
823 */
VinodKumarS-Huawei2ee9e7e2016-06-01 14:30:22 +0530824 private T getRefNode()
825 throws DataModelException {
Gaurav Agrawal0d43bb52016-05-17 18:06:38 +0530826 if (getCurrentEntityToResolveFromStack() instanceof YangType) {
827 YangDerivedInfo<?> derivedInfo = (YangDerivedInfo<?>)
828 ((YangType<?>) getCurrentEntityToResolveFromStack()).getDataTypeExtendedInfo();
829 return (T) derivedInfo.getReferredTypeDef();
830 } else if (getCurrentEntityToResolveFromStack() instanceof YangUses) {
831 return (T) ((YangUses) getCurrentEntityToResolveFromStack()).getRefGroup();
832 } else {
833 throw new DataModelException("Data Model Exception: Entity to resolved is other than type/uses");
834 }
835 }
836
837 /**
838 * Finds the referred grouping node at the root level of imported/included node.
839 *
840 * @param refNode module/sub-module node
841 * @return referred grouping
842 */
843 private YangNode findRefGrouping(YangNode refNode) {
844 YangNode tmpNode = refNode.getChild();
845 while (tmpNode != null) {
846 if (tmpNode instanceof YangGrouping) {
847 if (tmpNode.getName()
848 .equals(((YangUses) getCurrentEntityToResolveFromStack()).getName())) {
849 return tmpNode;
850 }
851 }
852 tmpNode = tmpNode.getNextSibling();
853 }
854 return null;
855 }
856
857 /**
858 * Finds the referred typedef node at the root level of imported/included node.
859 *
860 * @param refNode module/sub-module node
861 * @return referred typedef
862 */
863 private YangNode findRefTypedef(YangNode refNode) {
864 YangNode tmpNode = refNode.getChild();
865 while (tmpNode != null) {
866 if (tmpNode instanceof YangTypeDef) {
867 if (tmpNode.getName()
868 .equals(((YangType) getCurrentEntityToResolveFromStack()).getDataTypeName())) {
869 return tmpNode;
870 }
871 }
872 tmpNode = tmpNode.getNextSibling();
873 }
874 return null;
875 }
876}