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