2cd239b4381a3065f819fa9048018c5aafa79249
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / ParserUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.util;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Date;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.TreeMap;
17
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
20 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
21 import org.opendaylight.yangtools.yang.model.api.Module;
22 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
23 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
27 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
31 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
32 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
33 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
34 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
35 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
36 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
37 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
38 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
41 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
42 import org.opendaylight.yangtools.yang.model.util.BinaryType;
43 import org.opendaylight.yangtools.yang.model.util.BitsType;
44 import org.opendaylight.yangtools.yang.model.util.BooleanType;
45 import org.opendaylight.yangtools.yang.model.util.Decimal64;
46 import org.opendaylight.yangtools.yang.model.util.EmptyType;
47 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
48 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
49 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
50 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.model.util.Leafref;
52 import org.opendaylight.yangtools.yang.model.util.StringType;
53 import org.opendaylight.yangtools.yang.model.util.UnionType;
54 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
57 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder.ChoiceNodeImpl;
66 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder.ChoiceCaseNodeImpl;
68 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
69 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder.ContainerSchemaNodeImpl;
70 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
71 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
72 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder.ListSchemaNodeImpl;
73 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
74 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
75 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder.NotificationDefinitionImpl;
76 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
77
78 public final class ParserUtils {
79
80     private ParserUtils() {
81     }
82
83     /**
84      * Create new SchemaPath from given path and qname.
85      *
86      * @param schemaPath
87      * @param qname
88      * @return
89      */
90     public static SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
91         List<QName> path = new ArrayList<>(schemaPath.getPath());
92         path.addAll(Arrays.asList(qname));
93         return new SchemaPath(path, schemaPath.isAbsolute());
94     }
95
96     /**
97      * Get module import referenced by given prefix.
98      *
99      * @param builder
100      *            module to search
101      * @param prefix
102      *            prefix associated with import
103      * @return ModuleImport based on given prefix
104      */
105     public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
106         ModuleImport moduleImport = null;
107         for (ModuleImport mi : builder.getModuleImports()) {
108             if (mi.getPrefix().equals(prefix)) {
109                 moduleImport = mi;
110                 break;
111             }
112         }
113         return moduleImport;
114     }
115
116     /**
117      * Find dependent module based on given prefix
118      *
119      * @param modules
120      *            all available modules
121      * @param module
122      *            current module
123      * @param prefix
124      *            target module prefix
125      * @param line
126      *            current line in yang model
127      * @return module builder if found, null otherwise
128      */
129     public static ModuleBuilder findDependentModuleBuilder(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
130             final ModuleBuilder module, final String prefix, final int line) {
131         ModuleBuilder dependentModule = null;
132         Date dependentModuleRevision = null;
133
134         if (prefix.equals(module.getPrefix())) {
135             dependentModule = module;
136         } else {
137             final ModuleImport dependentModuleImport = getModuleImport(module, prefix);
138             if (dependentModuleImport == null) {
139                 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
140             }
141             final String dependentModuleName = dependentModuleImport.getModuleName();
142             dependentModuleRevision = dependentModuleImport.getRevision();
143
144             final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
145             if (moduleBuildersByRevision == null) {
146                 return null;
147             }
148             if (dependentModuleRevision == null) {
149                 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
150             } else {
151                 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
152             }
153         }
154         return dependentModule;
155     }
156
157     /**
158      * Find module from context based on prefix.
159      *
160      * @param context
161      *            schema context
162      * @param currentModule
163      *            current module
164      * @param prefix
165      *            current prefix used to reference dependent module
166      * @param line
167      *            current line in yang model
168      * @return module based on given prefix if found in context, null otherwise
169      */
170     public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
171             final String prefix, final int line) {
172         TreeMap<Date, Module> modulesByRevision = new TreeMap<Date, Module>();
173
174         final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
175         if (dependentModuleImport == null) {
176             throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
177         }
178         final String dependentModuleName = dependentModuleImport.getModuleName();
179         final Date dependentModuleRevision = dependentModuleImport.getRevision();
180
181         for (Module contextModule : context.getModules()) {
182             if (contextModule.getName().equals(dependentModuleName)) {
183                 Date revision = contextModule.getRevision();
184                 if (revision == null) {
185                     revision = new Date(0L);
186                 }
187                 modulesByRevision.put(revision, contextModule);
188                 break;
189             }
190         }
191
192         Module result = null;
193         if (dependentModuleRevision == null) {
194             result = modulesByRevision.get(modulesByRevision.firstKey());
195         } else {
196             result = modulesByRevision.get(dependentModuleRevision);
197         }
198
199         return result;
200     }
201
202     /**
203      * Parse XPath string.
204      *
205      * @param xpathString
206      *            as String
207      * @return SchemaPath from given String
208      */
209     public static SchemaPath parseXPathString(final String xpathString) {
210         final boolean absolute = xpathString.startsWith("/");
211         final String[] splittedPath = xpathString.split("/");
212         final List<QName> path = new ArrayList<QName>();
213         QName name;
214         for (String pathElement : splittedPath) {
215             if (pathElement.length() > 0) {
216                 final String[] splittedElement = pathElement.split(":");
217                 if (splittedElement.length == 1) {
218                     name = new QName(null, null, null, splittedElement[0]);
219                 } else {
220                     name = new QName(null, null, splittedElement[0], splittedElement[1]);
221                 }
222                 path.add(name);
223             }
224         }
225         return new SchemaPath(path, absolute);
226     }
227
228     /**
229      * Add all augment's child nodes to given target.
230      *
231      * @param augment
232      *            builder of augment statement
233      * @param target
234      *            augmentation target node
235      */
236     public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
237         for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
238             DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
239             childCopy.setAugmenting(true);
240             correctNodePath(child, target.getPath());
241             correctNodePath(childCopy, target.getPath());
242             try {
243                 target.addChildNode(childCopy);
244             } catch (YangParseException e) {
245                 // more descriptive message
246                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
247                         "Failed to perform augmentation: " + e.getMessage());
248             }
249
250         }
251         for (UsesNodeBuilder usesNode : augment.getUsesNodes()) {
252             UsesNodeBuilder copy = CopyUtils.copyUses(usesNode, target);
253             target.addUsesNode(copy);
254         }
255     }
256
257     /**
258      * Add all augment's child nodes to given target.
259      *
260      * @param augment
261      *            builder of augment statement
262      * @param target
263      *            augmentation target choice node
264      */
265     public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
266         for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
267             DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
268             childCopy.setAugmenting(true);
269             correctNodePath(builder, target.getPath());
270             correctNodePath(childCopy, target.getPath());
271             target.addCase(childCopy);
272         }
273         for (UsesNodeBuilder usesNode : augment.getUsesNodes()) {
274             if (usesNode != null) {
275                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
276                         "Error in augment parsing: cannot augment uses to choice");
277             }
278         }
279     }
280
281     static void correctNodePath(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath) {
282         // set correct path
283         List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
284         targetNodePath.add(node.getQName());
285         node.setPath(new SchemaPath(targetNodePath, true));
286
287         // set correct path for all child nodes
288         if (node instanceof DataNodeContainerBuilder) {
289             DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
290             for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
291                 correctNodePath(child, node.getPath());
292             }
293         }
294
295         // set correct path for all cases
296         if (node instanceof ChoiceBuilder) {
297             ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
298             for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
299                 correctNodePath(choiceCaseBuilder, node.getPath());
300             }
301         }
302
303         // if node can contains type, correct path for this type too
304         if (node instanceof TypeAwareBuilder) {
305             TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) node;
306             correctTypeAwareNodePath(nodeBuilder);
307         }
308     }
309
310     /**
311      * Repair schema path of node type.
312      *
313      * @param node
314      *            node which contains type statement
315      * @param parentSchemaPath
316      *            schema path of parent node
317      */
318     public static void correctTypeAwareNodePath(final TypeAwareBuilder node) {
319         final SchemaPath parentSchemaPath = node.getPath();
320         final TypeDefinition<?> nodeType = node.getType();
321
322         // handle union type
323         if (node instanceof UnionTypeBuilder) {
324             for (TypeDefinitionBuilder tdb : ((UnionTypeBuilder) node).getTypedefs()) {
325                 SchemaPath newSchemaPath = createSchemaPath(node.getPath(), tdb.getQName());
326                 tdb.setPath(newSchemaPath);
327                 correctTypeAwareNodePath(tdb);
328             }
329             List<TypeDefinition<?>> oldTypes = ((UnionTypeBuilder) node).getTypes();
330             List<TypeDefinition<?>> newTypes = new ArrayList<>();
331             for (TypeDefinition<?> td : oldTypes) {
332                 TypeDefinition<?> newType = createCorrectTypeDefinition(node.getPath(), td);
333                 newTypes.add(newType);
334             }
335             oldTypes.clear();
336             oldTypes.addAll(newTypes);
337             return;
338         }
339
340         // handle identityref type
341         if (node instanceof IdentityrefTypeBuilder) {
342             return;
343         }
344
345         // default handling
346         if (nodeType == null) {
347             TypeDefinitionBuilder nodeTypedef = node.getTypedef();
348             SchemaPath newSchemaPath = createSchemaPath(parentSchemaPath, nodeTypedef.getQName());
349             nodeTypedef.setPath(newSchemaPath);
350             correctTypeAwareNodePath(nodeTypedef);
351         } else {
352             TypeDefinition<?> newType = createCorrectTypeDefinition(parentSchemaPath, nodeType);
353             node.setType(newType);
354         }
355
356     }
357
358     public static TypeDefinition<?> createCorrectTypeDefinition(SchemaPath parentSchemaPath, TypeDefinition<?> nodeType) {
359         TypeDefinition<?> result = null;
360
361         if (nodeType != null) {
362             SchemaPath newSchemaPath = createSchemaPath(parentSchemaPath, nodeType.getQName());
363
364             if (nodeType instanceof BinaryTypeDefinition) {
365                 BinaryTypeDefinition binType = (BinaryTypeDefinition) nodeType;
366
367                 // List<Byte> bytes = (List<Byte>) binType.getDefaultValue();
368                 // workaround to get rid of 'Unchecked cast' warning
369                 List<Byte> bytes = new ArrayList<Byte>();
370                 Object defaultValue = binType.getDefaultValue();
371                 if (defaultValue instanceof List) {
372                     for (Object o : List.class.cast(defaultValue)) {
373                         if (o instanceof Byte) {
374                             bytes.add((Byte) o);
375                         }
376                     }
377                 }
378                 result = new BinaryType(newSchemaPath, bytes);
379             } else if (nodeType instanceof BitsTypeDefinition) {
380                 BitsTypeDefinition bitsType = (BitsTypeDefinition) nodeType;
381                 result = new BitsType(newSchemaPath, bitsType.getBits());
382             } else if (nodeType instanceof BooleanTypeDefinition) {
383                 result = new BooleanType(newSchemaPath);
384             } else if (nodeType instanceof DecimalTypeDefinition) {
385                 DecimalTypeDefinition decimalType = (DecimalTypeDefinition) nodeType;
386                 result = new Decimal64(newSchemaPath, decimalType.getFractionDigits());
387             } else if (nodeType instanceof EmptyTypeDefinition) {
388                 result = new EmptyType(newSchemaPath);
389             } else if (nodeType instanceof EnumTypeDefinition) {
390                 EnumTypeDefinition enumType = (EnumTypeDefinition) nodeType;
391                 result = new EnumerationType(newSchemaPath, (EnumPair) enumType.getDefaultValue(), enumType.getValues());
392             } else if (nodeType instanceof IdentityrefTypeDefinition) {
393                 IdentityrefTypeDefinition idrefType = (IdentityrefTypeDefinition) nodeType;
394                 result = new IdentityrefType(idrefType.getIdentity(), newSchemaPath);
395             } else if (nodeType instanceof InstanceIdentifierTypeDefinition) {
396                 InstanceIdentifierTypeDefinition instIdType = (InstanceIdentifierTypeDefinition) nodeType;
397                 return new InstanceIdentifier(newSchemaPath, instIdType.getPathStatement(),
398                         instIdType.requireInstance());
399             } else if (nodeType instanceof StringTypeDefinition) {
400                 result = new StringType(newSchemaPath);
401             } else if (nodeType instanceof IntegerTypeDefinition) {
402                 result = TypeUtils.createNewIntType(newSchemaPath, (IntegerTypeDefinition) nodeType);
403             } else if (nodeType instanceof UnsignedIntegerTypeDefinition) {
404                 result = TypeUtils.createNewUintType(newSchemaPath, (UnsignedIntegerTypeDefinition) nodeType);
405             } else if (nodeType instanceof LeafrefTypeDefinition) {
406                 result = new Leafref(newSchemaPath, ((LeafrefTypeDefinition) nodeType).getPathStatement());
407             } else if (nodeType instanceof UnionTypeDefinition) {
408                 UnionTypeDefinition unionType = (UnionTypeDefinition) nodeType;
409                 return new UnionType(newSchemaPath, unionType.getTypes());
410             } else if (nodeType instanceof ExtendedType) {
411                 ExtendedType extType = (ExtendedType) nodeType;
412                 result = TypeUtils.createNewExtendedType(extType, newSchemaPath);
413             }
414         }
415         return result;
416     }
417
418     /**
419      * Find augment target node and perform augmentation.
420      *
421      * @param augment
422      * @param firstNodeParent
423      *            parent of first node in path
424      * @param path
425      *            path to augment target
426      * @return true if augment process succeed, false otherwise
427      */
428     public static boolean processAugmentation(final AugmentationSchemaBuilder augment, final Builder firstNodeParent,
429             final List<QName> path) {
430         // traverse augment target path and try to reach target node
431         String currentName = null;
432         Builder currentParent = firstNodeParent;
433
434         for (int i = 0; i < path.size(); i++) {
435             QName qname = path.get(i);
436
437             currentName = qname.getLocalName();
438             if (currentParent instanceof DataNodeContainerBuilder) {
439                 DataSchemaNodeBuilder nodeFound = ((DataNodeContainerBuilder) currentParent)
440                         .getDataChildByName(currentName);
441                 // if not found as regular child, search in uses
442                 if (nodeFound == null) {
443                     boolean found = false;
444                     for (UsesNodeBuilder unb : ((DataNodeContainerBuilder) currentParent).getUsesNodes()) {
445                         DataSchemaNodeBuilder result = findNodeInUses(currentName, unb);
446                         if (result != null) {
447                             currentParent = result;
448                             found = true;
449                             break;
450                         }
451                     }
452                     // if not found even in uses nodes, return false
453                     if (!found) {
454                         return false;
455                     }
456                 } else {
457                     currentParent = nodeFound;
458                 }
459             } else if (currentParent instanceof ChoiceBuilder) {
460                 currentParent = ((ChoiceBuilder) currentParent).getCaseNodeByName(currentName);
461             } else {
462                 throw new YangParseException(augment.getModuleName(), augment.getLine(),
463                         "Error in augment parsing: failed to find node " + currentName);
464             }
465
466             // if node in path not found, return false
467             if (currentParent == null) {
468                 return false;
469             }
470         }
471         if (!(currentParent instanceof DataSchemaNodeBuilder)) {
472             throw new YangParseException(
473                     augment.getModuleName(),
474                     augment.getLine(),
475                     "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
476         }
477
478         if (currentParent instanceof ChoiceBuilder) {
479             fillAugmentTarget(augment, (ChoiceBuilder) currentParent);
480         } else {
481             fillAugmentTarget(augment, (DataNodeContainerBuilder) currentParent);
482         }
483         ((AugmentationTargetBuilder) currentParent).addAugmentation(augment);
484         SchemaPath oldPath = ((DataSchemaNodeBuilder) currentParent).getPath();
485         augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
486         augment.setResolved(true);
487
488         return true;
489     }
490
491     private static DataSchemaNodeBuilder findNodeInUses(String localName, UsesNodeBuilder uses) {
492         GroupingBuilder target = uses.getGroupingBuilder();
493         for (DataSchemaNodeBuilder child : target.getChildNodeBuilders()) {
494             if (child.getQName().getLocalName().equals(localName)) {
495                 return child;
496             }
497         }
498         for (UsesNodeBuilder usesNode : target.getUsesNodes()) {
499             DataSchemaNodeBuilder result = findNodeInUses(localName, usesNode);
500             if (result != null) {
501                 return result;
502             }
503         }
504         return null;
505     }
506
507     /**
508      * Find augment target node in given context and perform augmentation.
509      *
510      * @param augment
511      * @param path
512      *            path to augment target
513      * @param module
514      *            current module
515      * @param prefix
516      *            current prefix of target module
517      * @param context
518      *            SchemaContext containing already resolved modules
519      * @return true if augment process succeed, false otherwise
520      */
521     public static boolean processAugmentationOnContext(final AugmentationSchemaBuilder augment, final List<QName> path,
522             final ModuleBuilder module, final String prefix, final SchemaContext context) {
523         final int line = augment.getLine();
524         final Module dependentModule = findModuleFromContext(context, module, prefix, line);
525         if (dependentModule == null) {
526             throw new YangParseException(module.getName(), line,
527                     "Error in augment parsing: failed to find module with prefix " + prefix + ".");
528         }
529
530         String currentName = path.get(0).getLocalName();
531         SchemaNode currentParent = dependentModule.getDataChildByName(currentName);
532         if (currentParent == null) {
533             Set<NotificationDefinition> notifications = dependentModule.getNotifications();
534             for (NotificationDefinition ntf : notifications) {
535                 if (ntf.getQName().getLocalName().equals(currentName)) {
536                     currentParent = ntf;
537                     break;
538                 }
539             }
540         }
541         if (currentParent == null) {
542             throw new YangParseException(module.getName(), line, "Error in augment parsing: failed to find node "
543                     + currentName + ".");
544         }
545
546         for (int i = 1; i < path.size(); i++) {
547             currentName = path.get(i).getLocalName();
548             if (currentParent instanceof DataNodeContainer) {
549                 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(currentName);
550             } else if (currentParent instanceof ChoiceNode) {
551                 currentParent = ((ChoiceNode) currentParent).getCaseNodeByName(currentName);
552             } else {
553                 throw new YangParseException(augment.getModuleName(), line,
554                         "Error in augment parsing: failed to find node " + currentName);
555             }
556             // if node in path not found, return false
557             if (currentParent == null) {
558                 throw new YangParseException(module.getName(), line, "Error in augment parsing: failed to find node "
559                         + currentName + ".");
560             }
561         }
562
563         if (currentParent instanceof ContainerSchemaNodeImpl) {
564             // includes container, input and output statement
565             ContainerSchemaNodeImpl c = (ContainerSchemaNodeImpl) currentParent;
566             ContainerSchemaNodeBuilder cb = c.toBuilder();
567             fillAugmentTarget(augment, cb);
568             ((AugmentationTargetBuilder) cb).addAugmentation(augment);
569             SchemaPath oldPath = cb.getPath();
570             cb.rebuild();
571             augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
572             augment.setResolved(true);
573         } else if (currentParent instanceof ListSchemaNodeImpl) {
574             ListSchemaNodeImpl l = (ListSchemaNodeImpl) currentParent;
575             ListSchemaNodeBuilder lb = l.toBuilder();
576             fillAugmentTarget(augment, lb);
577             ((AugmentationTargetBuilder) lb).addAugmentation(augment);
578             SchemaPath oldPath = lb.getPath();
579             lb.rebuild();
580             augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
581             augment.setResolved(true);
582         } else if (currentParent instanceof ChoiceNodeImpl) {
583             ChoiceNodeImpl ch = (ChoiceNodeImpl) currentParent;
584             ChoiceBuilder chb = ch.toBuilder();
585             fillAugmentTarget(augment, chb);
586             ((AugmentationTargetBuilder) chb).addAugmentation(augment);
587             SchemaPath oldPath = chb.getPath();
588             chb.rebuild();
589             augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
590             augment.setResolved(true);
591         } else if (currentParent instanceof ChoiceCaseNodeImpl) {
592             ChoiceCaseNodeImpl chc = (ChoiceCaseNodeImpl) currentParent;
593             ChoiceCaseBuilder chcb = chc.toBuilder();
594             fillAugmentTarget(augment, chcb);
595             ((AugmentationTargetBuilder) chcb).addAugmentation(augment);
596             SchemaPath oldPath = chcb.getPath();
597             chcb.rebuild();
598             augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
599             augment.setResolved(true);
600         } else if (currentParent instanceof NotificationDefinitionImpl) {
601             NotificationDefinitionImpl nd = (NotificationDefinitionImpl) currentParent;
602             NotificationBuilder nb = nd.toBuilder();
603             fillAugmentTarget(augment, nb);
604             ((AugmentationTargetBuilder) nb).addAugmentation(augment);
605             SchemaPath oldPath = nb.getPath();
606             nb.rebuild();
607             augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
608             augment.setResolved(true);
609         } else {
610             throw new YangParseException(module.getName(), line, "Target of type " + currentParent.getClass()
611                     + " cannot be augmented.");
612         }
613
614         return true;
615     }
616
617     public static QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
618             final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
619         QName result = null;
620         String baseString = idref.getBaseString();
621         if (baseString.contains(":")) {
622             String[] splittedBase = baseString.split(":");
623             if (splittedBase.length > 2) {
624                 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
625                         + baseString);
626             }
627             String prefix = splittedBase[0];
628             String name = splittedBase[1];
629             ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
630             result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
631         } else {
632             result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
633         }
634         return result;
635     }
636
637     /**
638      * Get module in which this node is defined.
639      *
640      * @param node
641      * @return builder of module where this node is defined
642      */
643     public static ModuleBuilder getParentModule(Builder node) {
644         Builder parent = node.getParent();
645         while (!(parent instanceof ModuleBuilder)) {
646             parent = parent.getParent();
647         }
648         return (ModuleBuilder) parent;
649     }
650
651 }