Added support for parsing yang models with already resolved context.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / 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.controller.yang.parser.util;
9
10 import java.util.ArrayList;
11 import java.util.Collections;
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.controller.yang.common.QName;
19 import org.opendaylight.controller.yang.model.api.AnyXmlSchemaNode;
20 import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
21 import org.opendaylight.controller.yang.model.api.ChoiceNode;
22 import org.opendaylight.controller.yang.model.api.ConstraintDefinition;
23 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
24 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
25 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
26 import org.opendaylight.controller.yang.model.api.GroupingDefinition;
27 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
28 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
29 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
30 import org.opendaylight.controller.yang.model.api.Module;
31 import org.opendaylight.controller.yang.model.api.ModuleImport;
32 import org.opendaylight.controller.yang.model.api.MustDefinition;
33 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
34 import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
35 import org.opendaylight.controller.yang.model.api.SchemaContext;
36 import org.opendaylight.controller.yang.model.api.SchemaNode;
37 import org.opendaylight.controller.yang.model.api.SchemaPath;
38 import org.opendaylight.controller.yang.model.api.TypeDefinition;
39 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
40 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
41 import org.opendaylight.controller.yang.model.api.type.BooleanTypeDefinition;
42 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.EmptyTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
46 import org.opendaylight.controller.yang.model.api.type.IdentityrefTypeDefinition;
47 import org.opendaylight.controller.yang.model.api.type.InstanceIdentifierTypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
49 import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition;
50 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
51 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
52 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
53 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
54 import org.opendaylight.controller.yang.model.api.type.UnionTypeDefinition;
55 import org.opendaylight.controller.yang.model.api.type.UnsignedIntegerTypeDefinition;
56 import org.opendaylight.controller.yang.model.util.BinaryType;
57 import org.opendaylight.controller.yang.model.util.BitsType;
58 import org.opendaylight.controller.yang.model.util.BooleanType;
59 import org.opendaylight.controller.yang.model.util.Decimal64;
60 import org.opendaylight.controller.yang.model.util.EmptyType;
61 import org.opendaylight.controller.yang.model.util.EnumerationType;
62 import org.opendaylight.controller.yang.model.util.ExtendedType;
63 import org.opendaylight.controller.yang.model.util.IdentityrefType;
64 import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
65 import org.opendaylight.controller.yang.model.util.Int16;
66 import org.opendaylight.controller.yang.model.util.Int32;
67 import org.opendaylight.controller.yang.model.util.Int64;
68 import org.opendaylight.controller.yang.model.util.Int8;
69 import org.opendaylight.controller.yang.model.util.Leafref;
70 import org.opendaylight.controller.yang.model.util.StringType;
71 import org.opendaylight.controller.yang.model.util.Uint16;
72 import org.opendaylight.controller.yang.model.util.Uint32;
73 import org.opendaylight.controller.yang.model.util.Uint64;
74 import org.opendaylight.controller.yang.model.util.Uint8;
75 import org.opendaylight.controller.yang.model.util.UnionType;
76 import org.opendaylight.controller.yang.model.util.UnknownType;
77 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
78 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
79 import org.opendaylight.controller.yang.parser.builder.api.Builder;
80 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
81 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
82 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
83 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
84 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
85 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
86 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
87 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
88 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
89 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder.ChoiceNodeImpl;
90 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder;
91 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceCaseBuilder.ChoiceCaseNodeImpl;
92 import org.opendaylight.controller.yang.parser.builder.impl.ConstraintsBuilder;
93 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
94 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder.ContainerSchemaNodeImpl;
95 import org.opendaylight.controller.yang.parser.builder.impl.GroupingBuilderImpl;
96 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
97 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
98 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
99 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder.ListSchemaNodeImpl;
100 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
101 import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder;
102 import org.opendaylight.controller.yang.parser.builder.impl.NotificationBuilder.NotificationDefinitionImpl;
103 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
104 import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
105 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
106 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
107 import org.opendaylight.controller.yang.parser.builder.impl.UsesNodeBuilderImpl;
108
109 public final class ParserUtils {
110
111     private ParserUtils() {
112     }
113
114     /**
115      * Get module import referenced by given prefix.
116      *
117      * @param builder
118      *            module to search
119      * @param prefix
120      *            prefix associated with import
121      * @return ModuleImport based on given prefix
122      */
123     public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
124         ModuleImport moduleImport = null;
125         for (ModuleImport mi : builder.getModuleImports()) {
126             if (mi.getPrefix().equals(prefix)) {
127                 moduleImport = mi;
128                 break;
129             }
130         }
131         return moduleImport;
132     }
133
134     /**
135      * Find dependent module based on given prefix
136      *
137      * @param modules
138      *            all available modules
139      * @param module
140      *            current module
141      * @param prefix
142      *            target module prefix
143      * @param line
144      *            current line in yang model
145      * @return
146      */
147     public static ModuleBuilder findDependentModuleBuilder(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
148             final ModuleBuilder module, final String prefix, final int line) {
149         ModuleBuilder dependentModule = null;
150         Date dependentModuleRevision = null;
151
152         if (prefix.equals(module.getPrefix())) {
153             dependentModule = module;
154         } else {
155             final ModuleImport dependentModuleImport = getModuleImport(module, prefix);
156             if (dependentModuleImport == null) {
157                 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
158             }
159             final String dependentModuleName = dependentModuleImport.getModuleName();
160             dependentModuleRevision = dependentModuleImport.getRevision();
161
162             final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
163             if (moduleBuildersByRevision == null) {
164                 return null;
165             }
166             if (dependentModuleRevision == null) {
167                 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
168             } else {
169                 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
170             }
171         }
172         return dependentModule;
173     }
174
175     /**
176      * Find module from context based on prefix.
177      *
178      * @param context
179      *            schema context
180      * @param currentModule
181      *            current module
182      * @param prefix
183      *            current prefix used to reference dependent module
184      * @param line
185      *            current line in yang model
186      * @return module based on given prefix if found in context, null otherwise
187      */
188     public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
189             final String prefix, final int line) {
190         TreeMap<Date, Module> modulesByRevision = new TreeMap<Date, Module>();
191
192         Date dependentModuleRevision = null;
193
194         final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
195         if (dependentModuleImport == null) {
196             throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
197         }
198         final String dependentModuleName = dependentModuleImport.getModuleName();
199         dependentModuleRevision = dependentModuleImport.getRevision();
200
201         for (Module contextModule : context.getModules()) {
202             if (contextModule.getName().equals(dependentModuleName)) {
203                 Date revision = contextModule.getRevision();
204                 if (revision == null) {
205                     revision = new Date(0L);
206                 }
207                 modulesByRevision.put(revision, contextModule);
208                 break;
209             }
210         }
211
212         Module result = null;
213         if (dependentModuleRevision == null) {
214             result = modulesByRevision.get(modulesByRevision.firstKey());
215         } else {
216             result = modulesByRevision.get(dependentModuleRevision);
217         }
218
219         return result;
220     }
221
222     /**
223      * Find grouping by name.
224      *
225      * @param groupings
226      *            collection of grouping builders to search
227      * @param name
228      *            name of grouping
229      * @return grouping with given name if present in collection, null otherwise
230      */
231     public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
232         for (GroupingBuilder grouping : groupings) {
233             if (grouping.getQName().getLocalName().equals(name)) {
234                 return grouping;
235             }
236         }
237         return null;
238     }
239
240     /**
241      * Find grouping by name.
242      *
243      * @param groupings
244      *            collection of grouping definitions to search
245      * @param name
246      *            name of grouping
247      * @return grouping with given name if present in collection, null otherwise
248      */
249     public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
250         for (GroupingDefinition grouping : groupings) {
251             if (grouping.getQName().getLocalName().equals(name)) {
252                 return grouping;
253             }
254         }
255         return null;
256     }
257
258     /**
259      * Search types for type with given name.
260      *
261      * @param types
262      *            types to search
263      * @param name
264      *            name of type
265      * @return type with given name if present in collection, null otherwise
266      */
267     public static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
268         for (TypeDefinitionBuilder td : types) {
269             if (td.getQName().getLocalName().equals(name)) {
270                 return td;
271             }
272         }
273         return null;
274     }
275
276     /**
277      * Find type by name.
278      *
279      * @param types
280      *            collection of types
281      * @param typeName
282      *            type name
283      * @return type with given name if it is present in collection, null
284      *         otherwise
285      */
286     public static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
287         for (TypeDefinition<?> type : types) {
288             if (type.getQName().getLocalName().equals(typeName)) {
289                 return type;
290             }
291         }
292         return null;
293     }
294
295     /**
296      * Parse uses path.
297      *
298      * @param usesPath
299      *            as String
300      * @return SchemaPath from given String
301      */
302     public static SchemaPath parseUsesPath(final String usesPath) {
303         final boolean absolute = usesPath.startsWith("/");
304         final String[] splittedPath = usesPath.split("/");
305         final List<QName> path = new ArrayList<QName>();
306         QName name;
307         for (String pathElement : splittedPath) {
308             if (pathElement.length() > 0) {
309                 final String[] splittedElement = pathElement.split(":");
310                 if (splittedElement.length == 1) {
311                     name = new QName(null, null, null, splittedElement[0]);
312                 } else {
313                     name = new QName(null, null, splittedElement[0], splittedElement[1]);
314                 }
315                 path.add(name);
316             }
317         }
318         return new SchemaPath(path, absolute);
319     }
320
321     /**
322      * Pull restriction from type and add them to constraints.
323      *
324      * @param type
325      * @param constraints
326      */
327     public static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
328         if (type instanceof DecimalTypeDefinition) {
329             constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
330             constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
331         } else if (type instanceof IntegerTypeDefinition) {
332             constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
333         } else if (type instanceof StringTypeDefinition) {
334             constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
335             constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
336         } else if (type instanceof BinaryTypeDefinition) {
337             constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
338         }
339     }
340
341     /**
342      * Find node in grouping by name.
343      *
344      * @param grouping
345      *            grouping to search
346      * @param refineNodeName
347      *            name of node
348      * @return builder of node with given name if present in grouping, null
349      *         otherwise
350      */
351     public static Builder findRefineTargetBuilder(final GroupingBuilder grouping, final String refineNodeName) {
352         // search child nodes
353         Builder result = grouping.getChildNode(refineNodeName);
354         // search groupings
355         if (result == null) {
356             Set<GroupingBuilder> grps = grouping.getGroupings();
357             for (GroupingBuilder gr : grps) {
358                 if (gr.getQName().getLocalName().equals(refineNodeName)) {
359                     result = gr;
360                     break;
361                 }
362             }
363         }
364         // search typedefs
365         if (result == null) {
366             Set<TypeDefinitionBuilder> typedefs = grouping.getTypeDefinitions();
367             for (TypeDefinitionBuilder typedef : typedefs) {
368                 if (typedef.getQName().getLocalName().equals(refineNodeName)) {
369                     result = typedef;
370                     break;
371                 }
372             }
373         }
374         return result;
375     }
376
377     /**
378      * Find node in grouping by name.
379      *
380      * @param builder
381      *            grouping to search
382      * @param refineNodeName
383      *            name of node
384      * @return node with given name if present in grouping, null otherwise
385      */
386     public static Object findRefineTargetNode(final GroupingDefinition builder, final String refineNodeName) {
387         Object result = builder.getDataChildByName(refineNodeName);
388         if (result == null) {
389             Set<GroupingDefinition> grps = builder.getGroupings();
390             for (GroupingDefinition gr : grps) {
391                 if (gr.getQName().getLocalName().equals(refineNodeName)) {
392                     result = gr;
393                     break;
394                 }
395             }
396         }
397         if (result == null) {
398             Set<TypeDefinition<?>> typedefs = builder.getTypeDefinitions();
399             for (TypeDefinition<?> typedef : typedefs) {
400                 if (typedef.getQName().getLocalName().equals(refineNodeName)) {
401                     result = typedef;
402                     break;
403                 }
404             }
405         }
406         return result;
407     }
408
409     /**
410      * Add all augment's child nodes to given target.
411      *
412      * @param augment
413      *            builder of augment statement
414      * @param target
415      *            augmentation target node
416      */
417     public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
418         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
419             builder.setAugmenting(true);
420             correctAugmentChildPath(builder, target.getPath());
421             target.addChildNode(builder);
422         }
423     }
424
425     /**
426      * Add all augment's child nodes to given target.
427      *
428      * @param augment
429      *            builder of augment statement
430      * @param target
431      *            augmentation target choice node
432      */
433     public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
434         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
435             builder.setAugmenting(true);
436             correctAugmentChildPath(builder, target.getPath());
437             target.addChildNode(builder);
438         }
439     }
440
441     private static void correctAugmentChildPath(final DataSchemaNodeBuilder childNode, final SchemaPath parentSchemaPath) {
442         // set correct path
443         List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
444         targetNodePath.add(childNode.getQName());
445         childNode.setPath(new SchemaPath(targetNodePath, true));
446
447         // set correct path for all child nodes
448         if (childNode instanceof DataNodeContainerBuilder) {
449             DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) childNode;
450             for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodes()) {
451                 correctAugmentChildPath(child, childNode.getPath());
452             }
453         }
454
455         // if node can contains type, correct path for this type too
456         if (childNode instanceof TypeAwareBuilder) {
457             TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) childNode;
458             correctTypeAwareNodePath(nodeBuilder, parentSchemaPath);
459         }
460     }
461
462     /**
463      * Repair schema path of node type.
464      *
465      * @param node
466      *            node which contains type statement
467      * @param parentSchemaPath
468      *            schema path of parent node
469      */
470     private static void correctTypeAwareNodePath(final TypeAwareBuilder node, final SchemaPath parentSchemaPath) {
471         final QName nodeBuilderQName = node.getQName();
472         final TypeDefinition<?> nodeType = node.getType();
473
474         Integer fd = null;
475         List<LengthConstraint> lengths = null;
476         List<PatternConstraint> patterns = null;
477         List<RangeConstraint> ranges = null;
478
479         if (nodeType != null) {
480             if (nodeType instanceof ExtendedType) {
481                 ExtendedType et = (ExtendedType) nodeType;
482                 if (nodeType.getQName().getLocalName().equals(nodeType.getBaseType().getQName().getLocalName())) {
483                     fd = et.getFractionDigits();
484                     lengths = et.getLengths();
485                     patterns = et.getPatterns();
486                     ranges = et.getRanges();
487                     if (!hasConstraints(fd, lengths, patterns, ranges)) {
488                         return;
489                     }
490                 }
491             }
492             TypeDefinition<?> newType = createCorrectTypeDefinition(parentSchemaPath, nodeBuilderQName, nodeType);
493             node.setType(newType);
494         } else {
495             TypeDefinitionBuilder nodeBuilderTypedef = node.getTypedef();
496
497             fd = nodeBuilderTypedef.getFractionDigits();
498             lengths = nodeBuilderTypedef.getLengths();
499             patterns = nodeBuilderTypedef.getPatterns();
500             ranges = nodeBuilderTypedef.getRanges();
501
502             String tdbTypeName = nodeBuilderTypedef.getQName().getLocalName();
503             String baseTypeName = null;
504             if (nodeBuilderTypedef.getType() == null) {
505                 baseTypeName = nodeBuilderTypedef.getTypedef().getQName().getLocalName();
506             } else {
507                 baseTypeName = nodeBuilderTypedef.getType().getQName().getLocalName();
508             }
509             if (!(tdbTypeName.equals(baseTypeName))) {
510                 return;
511             }
512
513             if (!hasConstraints(fd, lengths, patterns, ranges)) {
514                 return;
515             }
516
517             SchemaPath newSchemaPath = createNewSchemaPath(nodeBuilderTypedef.getPath(), nodeBuilderQName,
518                     nodeBuilderTypedef.getQName());
519             nodeBuilderTypedef.setPath(newSchemaPath);
520         }
521     }
522
523     /**
524      * Check if there are some constraints.
525      *
526      * @param fd
527      *            fraction digits
528      * @param lengths
529      *            length constraints
530      * @param patterns
531      *            pattern constraints
532      * @param ranges
533      *            range constraints
534      * @return true, if any of constraints are present, false otherwise
535      */
536     private static boolean hasConstraints(final Integer fd, final List<LengthConstraint> lengths,
537             final List<PatternConstraint> patterns, final List<RangeConstraint> ranges) {
538         if (fd == null && (lengths == null || lengths.isEmpty()) && (patterns == null || patterns.isEmpty())
539                 && (ranges == null || ranges.isEmpty())) {
540             return false;
541         } else {
542             return true;
543         }
544     }
545
546     private static TypeDefinition<?> createCorrectTypeDefinition(SchemaPath parentSchemaPath, QName nodeQName,
547             TypeDefinition<?> nodeType) {
548         QName nodeTypeQName = nodeType.getQName();
549         SchemaPath newSchemaPath = createNewSchemaPath(parentSchemaPath, nodeQName, nodeTypeQName);
550         TypeDefinition<?> result = null;
551
552         if (nodeType != null) {
553             if (nodeType instanceof BinaryTypeDefinition) {
554                 BinaryTypeDefinition binType = (BinaryTypeDefinition) nodeType;
555
556                 // List<Byte> bytes = (List<Byte>) binType.getDefaultValue();
557                 // workaround to get rid of 'Unchecked cast' warning
558                 List<Byte> bytes = new ArrayList<Byte>();
559                 Object defaultValue = binType.getDefaultValue();
560                 if (defaultValue instanceof List) {
561                     for (Object o : List.class.cast(defaultValue)) {
562                         if (o instanceof Byte) {
563                             bytes.add((Byte) o);
564                         }
565                     }
566                 }
567                 result = new BinaryType(newSchemaPath, bytes);
568             } else if (nodeType instanceof BitsTypeDefinition) {
569                 BitsTypeDefinition bitsType = (BitsTypeDefinition) nodeType;
570                 result = new BitsType(newSchemaPath, bitsType.getBits());
571             } else if (nodeType instanceof BooleanTypeDefinition) {
572                 result = new BooleanType(newSchemaPath);
573             } else if (nodeType instanceof DecimalTypeDefinition) {
574                 DecimalTypeDefinition decimalType = (DecimalTypeDefinition) nodeType;
575                 result = new Decimal64(newSchemaPath, decimalType.getFractionDigits());
576             } else if (nodeType instanceof EmptyTypeDefinition) {
577                 result = new EmptyType(newSchemaPath);
578             } else if (nodeType instanceof EnumTypeDefinition) {
579                 EnumTypeDefinition enumType = (EnumTypeDefinition) nodeType;
580                 result = new EnumerationType(newSchemaPath, (EnumPair) enumType.getDefaultValue(), enumType.getValues());
581             } else if (nodeType instanceof IdentityrefTypeDefinition) {
582                 IdentityrefTypeDefinition idrefType = (IdentityrefTypeDefinition) nodeType;
583                 result = new IdentityrefType(idrefType.getIdentity(), newSchemaPath);
584             } else if (nodeType instanceof InstanceIdentifierTypeDefinition) {
585                 InstanceIdentifierTypeDefinition instIdType = (InstanceIdentifierTypeDefinition) nodeType;
586                 return new InstanceIdentifier(newSchemaPath, instIdType.getPathStatement(),
587                         instIdType.requireInstance());
588             } else if (nodeType instanceof StringTypeDefinition) {
589                 result = createNewStringType(parentSchemaPath, nodeQName, (StringTypeDefinition) nodeType);
590             } else if (nodeType instanceof IntegerTypeDefinition) {
591                 result = createNewIntType(parentSchemaPath, nodeQName, (IntegerTypeDefinition) nodeType);
592             } else if (nodeType instanceof UnsignedIntegerTypeDefinition) {
593                 result = createNewUintType(parentSchemaPath, nodeQName, (UnsignedIntegerTypeDefinition) nodeType);
594             } else if (nodeType instanceof LeafrefTypeDefinition) {
595                 result = new Leafref(newSchemaPath, ((LeafrefTypeDefinition) nodeType).getPathStatement());
596             } else if (nodeType instanceof UnionTypeDefinition) {
597                 UnionTypeDefinition unionType = (UnionTypeDefinition) nodeType;
598                 return new UnionType(newSchemaPath, unionType.getTypes());
599             } else if (nodeType instanceof ExtendedType) {
600                 ExtendedType extType = (ExtendedType) nodeType;
601                 result = createNewExtendedType(extType, newSchemaPath);
602             }
603         }
604         return result;
605     }
606
607     /**
608      * Create new ExtendedType based on given type and with schema path.
609      *
610      * @param newPath
611      *            schema path for new type
612      * @param oldType
613      *            type based
614      * @return
615      */
616     private static ExtendedType createNewExtendedType(final ExtendedType oldType, final SchemaPath newPath) {
617         QName qname = oldType.getQName();
618         TypeDefinition<?> baseType = oldType.getBaseType();
619         String desc = oldType.getDescription();
620         String ref = oldType.getReference();
621         ExtendedType.Builder builder = new ExtendedType.Builder(qname, baseType, desc, ref, newPath);
622         builder.status(oldType.getStatus());
623         builder.lengths(oldType.getLengths());
624         builder.patterns(oldType.getPatterns());
625         builder.ranges(oldType.getRanges());
626         builder.fractionDigits(oldType.getFractionDigits());
627         builder.unknownSchemaNodes(oldType.getUnknownSchemaNodes());
628         return builder.build();
629     }
630
631     private static StringTypeDefinition createNewStringType(final SchemaPath schemaPath, final QName nodeQName,
632             final StringTypeDefinition nodeType) {
633         final List<QName> path = schemaPath.getPath();
634         final List<QName> newPath = new ArrayList<QName>(path);
635         newPath.add(nodeQName);
636         newPath.add(nodeType.getQName());
637         final SchemaPath newSchemaPath = new SchemaPath(newPath, schemaPath.isAbsolute());
638         return new StringType(newSchemaPath);
639     }
640
641     private static IntegerTypeDefinition createNewIntType(final SchemaPath schemaPath, final QName nodeQName,
642             final IntegerTypeDefinition type) {
643         final QName typeQName = type.getQName();
644         final SchemaPath newSchemaPath = createNewSchemaPath(schemaPath, nodeQName, typeQName);
645         final String localName = typeQName.getLocalName();
646
647         if ("int8".equals(localName)) {
648             return new Int8(newSchemaPath);
649         } else if ("int16".equals(localName)) {
650             return new Int16(newSchemaPath);
651         } else if ("int32".equals(localName)) {
652             return new Int32(newSchemaPath);
653         } else if ("int64".equals(localName)) {
654             return new Int64(newSchemaPath);
655         } else {
656             return null;
657         }
658     }
659
660     private static UnsignedIntegerTypeDefinition createNewUintType(final SchemaPath schemaPath, final QName nodeQName,
661             final UnsignedIntegerTypeDefinition type) {
662         final QName typeQName = type.getQName();
663         final SchemaPath newSchemaPath = createNewSchemaPath(schemaPath, nodeQName, typeQName);
664         final String localName = typeQName.getLocalName();
665
666         if ("uint8".equals(localName)) {
667             return new Uint8(newSchemaPath);
668         } else if ("uint16".equals(localName)) {
669             return new Uint16(newSchemaPath);
670         } else if ("uint32".equals(localName)) {
671             return new Uint32(newSchemaPath);
672         } else if ("uint64".equals(localName)) {
673             return new Uint64(newSchemaPath);
674         } else {
675             return null;
676         }
677     }
678
679     private static SchemaPath createNewSchemaPath(final SchemaPath schemaPath, final QName currentQName,
680             final QName qname) {
681         List<QName> newPath = new ArrayList<QName>(schemaPath.getPath());
682         newPath.add(currentQName);
683         newPath.add(qname);
684         return new SchemaPath(newPath, schemaPath.isAbsolute());
685     }
686
687     public static LeafSchemaNodeBuilder copyLeafBuilder(final LeafSchemaNodeBuilder old) {
688         final LeafSchemaNodeBuilder copy = new LeafSchemaNodeBuilder(old.getQName(), old.getLine());
689         final TypeDefinition<?> type = old.getType();
690         if (type == null) {
691             copy.setTypedef(old.getTypedef());
692         } else {
693             copy.setType(type);
694         }
695         copyDataSchemaNodeArgs(old, copy);
696         copyConstraintsFromBuilder(old, copy);
697         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
698             copy.addUnknownSchemaNode(unknown);
699         }
700         copy.setDefaultStr(old.getDefaultStr());
701         copy.setUnits(old.getUnits());
702         return copy;
703     }
704
705     public static ContainerSchemaNodeBuilder copyContainerBuilder(final ContainerSchemaNodeBuilder old) {
706         final ContainerSchemaNodeBuilder copy = new ContainerSchemaNodeBuilder(old.getQName(), old.getLine());
707         copyDataSchemaNodeArgs(old, copy);
708         copyConstraintsFromBuilder(old, copy);
709         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
710             copy.addUnknownSchemaNode(unknown);
711         }
712         for (DataSchemaNodeBuilder child : old.getChildNodes()) {
713             copy.addChildNode(child);
714         }
715         for (GroupingBuilder grouping : old.getGroupings()) {
716             copy.addGrouping(grouping);
717         }
718         for (TypeDefinitionBuilder typedef : old.getTypeDefinitions()) {
719             copy.addTypedef(typedef);
720         }
721         for (AugmentationSchemaBuilder augment : old.getAugmentations()) {
722             copy.addAugmentation(augment);
723         }
724         for (UsesNodeBuilder use : old.getUsesNodes()) {
725             copy.addUsesNode(use);
726         }
727         copy.setPresence(old.isPresence());
728         return copy;
729     }
730
731     public static ListSchemaNodeBuilder copyListBuilder(final ListSchemaNodeBuilder old) {
732         final ListSchemaNodeBuilder copy = new ListSchemaNodeBuilder(old.getQName(), old.getLine());
733         copyDataSchemaNodeArgs(old, copy);
734         copyConstraintsFromBuilder(old, copy);
735         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
736             copy.addUnknownSchemaNode(unknown);
737         }
738         for (DataSchemaNodeBuilder child : old.getChildNodes()) {
739             copy.addChildNode(child);
740         }
741         for (GroupingBuilder grouping : old.getGroupings()) {
742             copy.addGrouping(grouping);
743         }
744         for (TypeDefinitionBuilder typedef : old.getTypeDefinitions()) {
745             copy.addTypedef(typedef);
746         }
747         for (AugmentationSchemaBuilder augment : old.getAugmentations()) {
748             copy.addAugmentation(augment);
749         }
750         for (UsesNodeBuilder use : old.getUsesNodes()) {
751             copy.addUsesNode(use);
752         }
753         copy.setUserOrdered(old.isUserOrdered());
754         return copy;
755     }
756
757     public static LeafListSchemaNodeBuilder copyLeafListBuilder(final LeafListSchemaNodeBuilder old) {
758         final LeafListSchemaNodeBuilder copy = new LeafListSchemaNodeBuilder(old.getQName(), old.getLine());
759         copyDataSchemaNodeArgs(old, copy);
760         copyConstraintsFromBuilder(old, copy);
761         final TypeDefinition<?> type = old.getType();
762         if (type == null) {
763             copy.setTypedef(old.getTypedef());
764         } else {
765             copy.setType(type);
766         }
767         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
768             copy.addUnknownSchemaNode(unknown);
769         }
770         copy.setUserOrdered(old.isUserOrdered());
771         return copy;
772     }
773
774     public static ChoiceBuilder copyChoiceBuilder(final ChoiceBuilder old) {
775         final ChoiceBuilder copy = new ChoiceBuilder(old.getQName(), old.getLine());
776         copyDataSchemaNodeArgs(old, copy);
777         copyConstraintsFromBuilder(old, copy);
778         for (ChoiceCaseBuilder caseBuilder : old.getCases()) {
779             copy.addChildNode(caseBuilder);
780         }
781         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
782             copy.addUnknownSchemaNode(unknown);
783         }
784         copy.setDefaultCase(old.getDefaultCase());
785         return copy;
786     }
787
788     public static AnyXmlBuilder copyAnyXmlBuilder(final AnyXmlBuilder old) {
789         final AnyXmlBuilder copy = new AnyXmlBuilder(old.getQName(), old.getLine());
790         copyDataSchemaNodeArgs(old, copy);
791         copyConstraintsFromBuilder(old, copy);
792         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
793             copy.addUnknownSchemaNode(unknown);
794         }
795         return copy;
796     }
797
798     public static GroupingBuilder copyGroupingBuilder(final GroupingBuilder old) {
799         final GroupingBuilder copy = new GroupingBuilderImpl(old.getQName(), old.getLine());
800         copy.setPath(old.getPath());
801         for (DataSchemaNodeBuilder child : old.getChildNodes()) {
802             copy.addChildNode(child);
803         }
804         for (GroupingBuilder grouping : old.getGroupings()) {
805             copy.addGrouping(grouping);
806         }
807         for (TypeDefinitionBuilder typedef : old.getTypeDefinitions()) {
808             copy.addTypedef(typedef);
809         }
810         for (UsesNodeBuilder use : old.getUses()) {
811             copy.addUsesNode(use);
812         }
813         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
814             copy.addUnknownSchemaNode(unknown);
815         }
816         copy.setDescription(old.getDescription());
817         copy.setReference(old.getReference());
818         copy.setStatus(old.getStatus());
819         return copy;
820     }
821
822     public static TypeDefinitionBuilderImpl copyTypedefBuilder(final TypeDefinitionBuilderImpl old) {
823         final TypeDefinitionBuilderImpl copy = new TypeDefinitionBuilderImpl(old.getQName(), old.getLine());
824         copy.setPath(old.getPath());
825         copy.setDefaultValue(old.getDefaultValue());
826         copy.setUnits(old.getUnits());
827         copy.setDescription(old.getDescription());
828         copy.setReference(old.getReference());
829         copy.setStatus(old.getStatus());
830
831         copy.setRanges(old.getRanges());
832         copy.setLengths(old.getLengths());
833         copy.setPatterns(old.getPatterns());
834         copy.setFractionDigits(old.getFractionDigits());
835
836         TypeDefinition<?> type = old.getType();
837         if (type == null) {
838             copy.setTypedef(old.getTypedef());
839         } else {
840             copy.setType(old.getType());
841         }
842         copy.setUnits(old.getUnits());
843         for (UnknownSchemaNodeBuilder unknown : old.getUnknownNodes()) {
844             copy.addUnknownSchemaNode(unknown);
845         }
846         return copy;
847     }
848
849     public static UsesNodeBuilder copyUsesNodeBuilder(final UsesNodeBuilder old) {
850         final UsesNodeBuilder copy = new UsesNodeBuilderImpl(old.getGroupingName(), old.getLine());
851         for (AugmentationSchemaBuilder augment : old.getAugmentations()) {
852             copy.addAugment(augment);
853         }
854         copy.setAugmenting(old.isAugmenting());
855         for (SchemaNodeBuilder refineNode : old.getRefineNodes()) {
856             copy.addRefineNode(refineNode);
857         }
858         return copy;
859     }
860
861     private static void copyDataSchemaNodeArgs(final DataSchemaNodeBuilder oldBuilder,
862             final DataSchemaNodeBuilder newBuilder) {
863         newBuilder.setPath(oldBuilder.getPath());
864         newBuilder.setDescription(oldBuilder.getDescription());
865         newBuilder.setReference(oldBuilder.getReference());
866         newBuilder.setStatus(oldBuilder.getStatus());
867         newBuilder.setAugmenting(oldBuilder.isAugmenting());
868         if (!(oldBuilder instanceof ChoiceCaseNode)) {
869             newBuilder.setConfiguration(oldBuilder.isConfiguration());
870         }
871     }
872
873     /**
874      * Copy constraints from old builder to new builder.
875      *
876      * @param oldBuilder
877      * @param newBuilder
878      */
879     private static void copyConstraintsFromBuilder(final DataSchemaNodeBuilder oldBuilder,
880             final DataSchemaNodeBuilder newBuilder) {
881         final ConstraintsBuilder oldConstraints = oldBuilder.getConstraints();
882         final ConstraintsBuilder newConstraints = newBuilder.getConstraints();
883         newConstraints.addWhenCondition(oldConstraints.getWhenCondition());
884         for (MustDefinition must : oldConstraints.getMustDefinitions()) {
885             newConstraints.addMustDefinition(must);
886         }
887         newConstraints.setMandatory(oldConstraints.isMandatory());
888         newConstraints.setMinElements(oldConstraints.getMinElements());
889         newConstraints.setMaxElements(oldConstraints.getMaxElements());
890     }
891
892     /**
893      * Create LeafSchemaNodeBuilder from given LeafSchemaNode.
894      *
895      * @param leaf
896      *            leaf from which to create builder
897      * @param line
898      *            line in module
899      * @return builder object from leaf
900      */
901     public static LeafSchemaNodeBuilder createLeafBuilder(LeafSchemaNode leaf, int line) {
902         final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(leaf.getQName(), line);
903         convertDataSchemaNode(leaf, builder);
904         final TypeDefinition<?> type = leaf.getType();
905         builder.setType(type);
906         builder.setPath(leaf.getPath());
907         builder.setUnknownNodes(leaf.getUnknownSchemaNodes());
908         builder.setDefaultStr(leaf.getDefault());
909         builder.setUnits(leaf.getUnits());
910         return builder;
911     }
912
913     public static ContainerSchemaNodeBuilder createContainer(ContainerSchemaNode container, int line) {
914         final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(container.getQName(), line);
915         convertDataSchemaNode(container, builder);
916         builder.setUnknownNodes(container.getUnknownSchemaNodes());
917         builder.setChildNodes(container.getChildNodes());
918         builder.setGroupings(container.getGroupings());
919         builder.setTypedefs(container.getTypeDefinitions());
920         builder.setAugmentations(container.getAvailableAugmentations());
921         builder.setUsesnodes(container.getUses());
922         builder.setPresence(container.isPresenceContainer());
923         return builder;
924     }
925
926     public static ListSchemaNodeBuilder createList(ListSchemaNode list, int line) {
927         ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(list.getQName(), line);
928         convertDataSchemaNode(list, builder);
929         builder.setUnknownNodes(list.getUnknownSchemaNodes());
930         builder.setTypedefs(list.getTypeDefinitions());
931         builder.setChildNodes(list.getChildNodes());
932         builder.setGroupings(list.getGroupings());
933         builder.setAugmentations(list.getAvailableAugmentations());
934         builder.setUsesnodes(list.getUses());
935         builder.setUserOrdered(builder.isUserOrdered());
936         return builder;
937     }
938
939     public static LeafListSchemaNodeBuilder createLeafList(LeafListSchemaNode leafList, int line) {
940         final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(leafList.getQName(), line);
941         convertDataSchemaNode(leafList, builder);
942         builder.setType(leafList.getType());
943         builder.setUnknownNodes(leafList.getUnknownSchemaNodes());
944         builder.setUserOrdered(leafList.isUserOrdered());
945         return builder;
946     }
947
948     public static ChoiceBuilder createChoice(ChoiceNode choice, int line) {
949         final ChoiceBuilder builder = new ChoiceBuilder(choice.getQName(), line);
950         convertDataSchemaNode(choice, builder);
951         builder.setCases(choice.getCases());
952         builder.setUnknownNodes(choice.getUnknownSchemaNodes());
953         builder.setDefaultCase(choice.getDefaultCase());
954         return builder;
955     }
956
957     public static AnyXmlBuilder createAnyXml(AnyXmlSchemaNode anyxml, int line) {
958         final AnyXmlBuilder builder = new AnyXmlBuilder(anyxml.getQName(), line);
959         convertDataSchemaNode(anyxml, builder);
960         builder.setUnknownNodes(anyxml.getUnknownSchemaNodes());
961         return builder;
962     }
963
964     public static GroupingBuilder createGrouping(GroupingDefinition grouping, int line) {
965         final GroupingBuilderImpl builder = new GroupingBuilderImpl(grouping.getQName(), line);
966         builder.setPath(grouping.getPath());
967         builder.setChildNodes(grouping.getChildNodes());
968         builder.setGroupings(grouping.getGroupings());
969         builder.setTypedefs(grouping.getTypeDefinitions());
970         builder.setUsesnodes(grouping.getUses());
971         builder.setUnknownNodes(grouping.getUnknownSchemaNodes());
972         builder.setDescription(grouping.getDescription());
973         builder.setReference(grouping.getReference());
974         builder.setStatus(grouping.getStatus());
975         return builder;
976     }
977
978     public static TypeDefinitionBuilder createTypedef(ExtendedType typedef, int line) {
979         final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(typedef.getQName(), line);
980         builder.setPath(typedef.getPath());
981         builder.setDefaultValue(typedef.getDefaultValue());
982         builder.setUnits(typedef.getUnits());
983         builder.setDescription(typedef.getDescription());
984         builder.setReference(typedef.getReference());
985         builder.setStatus(typedef.getStatus());
986         builder.setRanges(typedef.getRanges());
987         builder.setLengths(typedef.getLengths());
988         builder.setPatterns(typedef.getPatterns());
989         builder.setFractionDigits(typedef.getFractionDigits());
990         final TypeDefinition<?> type = typedef.getBaseType();
991         builder.setType(type);
992         builder.setUnits(typedef.getUnits());
993         builder.setUnknownNodes(typedef.getUnknownSchemaNodes());
994         return builder;
995     }
996
997     /**
998      * Set DataSchemaNode arguments to builder object
999      *
1000      * @param node
1001      *            node from which arguments should be read
1002      * @param builder
1003      *            builder to which arguments should be set
1004      */
1005     private static void convertDataSchemaNode(DataSchemaNode node, DataSchemaNodeBuilder builder) {
1006         builder.setPath(node.getPath());
1007         builder.setDescription(node.getDescription());
1008         builder.setReference(node.getReference());
1009         builder.setStatus(node.getStatus());
1010         builder.setAugmenting(node.isAugmenting());
1011         if (!(node instanceof ChoiceCaseNode)) {
1012             builder.setConfiguration(node.isConfiguration());
1013         }
1014         copyConstraintsFromDefinition(node.getConstraints(), builder.getConstraints());
1015     }
1016
1017     /**
1018      * Copy constraints from constraints definition to constraints builder.
1019      *
1020      * @param nodeConstraints
1021      *            definition from which constraints will be copied
1022      * @param constraints
1023      *            builder to which constraints will be added
1024      */
1025     private static void copyConstraintsFromDefinition(final ConstraintDefinition nodeConstraints,
1026             final ConstraintsBuilder constraints) {
1027         final RevisionAwareXPath when = nodeConstraints.getWhenCondition();
1028         final Set<MustDefinition> must = nodeConstraints.getMustConstraints();
1029
1030         if (when != null) {
1031             constraints.addWhenCondition(when.toString());
1032         }
1033         if (must != null) {
1034             for (MustDefinition md : must) {
1035                 constraints.addMustDefinition(md);
1036             }
1037         }
1038         constraints.setMandatory(nodeConstraints.isMandatory());
1039         constraints.setMinElements(nodeConstraints.getMinElements());
1040         constraints.setMaxElements(nodeConstraints.getMaxElements());
1041     }
1042
1043     public static void processAugmentationOnContext(final AugmentationSchemaBuilder augmentBuilder,
1044             final List<QName> path, final ModuleBuilder module, final String prefix, final int line,
1045             final SchemaContext context) {
1046         final Module dependentModule = findModuleFromContext(context, module, prefix, line);
1047         if (dependentModule == null) {
1048             throw new YangParseException(module.getName(), line, "Failed to find referenced module with prefix "
1049                     + prefix + ".");
1050         }
1051         SchemaNode node = dependentModule.getDataChildByName(path.get(0).getLocalName());
1052         if (node == null) {
1053             Set<NotificationDefinition> notifications = dependentModule.getNotifications();
1054             for (NotificationDefinition ntf : notifications) {
1055                 if (ntf.getQName().getLocalName().equals(path.get(0).getLocalName())) {
1056                     node = ntf;
1057                     break;
1058                 }
1059             }
1060         }
1061         if (node == null) {
1062             return;
1063         }
1064
1065         for (int i = 1; i < path.size(); i++) {
1066             if (node instanceof DataNodeContainer) {
1067                 DataNodeContainer ref = (DataNodeContainer) node;
1068                 node = ref.getDataChildByName(path.get(i).getLocalName());
1069             }
1070         }
1071         if (node == null) {
1072             return;
1073         }
1074
1075         if (node instanceof ContainerSchemaNodeImpl) {
1076             // includes container, input and output statement
1077             ContainerSchemaNodeImpl c = (ContainerSchemaNodeImpl) node;
1078             ContainerSchemaNodeBuilder cb = c.toBuilder();
1079             fillAugmentTarget(augmentBuilder, cb);
1080             ((AugmentationTargetBuilder) cb).addAugmentation(augmentBuilder);
1081             SchemaPath oldPath = cb.getPath();
1082             cb.rebuild();
1083             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1084             augmentBuilder.setResolved(true);
1085             module.augmentResolved();
1086         } else if (node instanceof ListSchemaNodeImpl) {
1087             ListSchemaNodeImpl l = (ListSchemaNodeImpl) node;
1088             ListSchemaNodeBuilder lb = l.toBuilder();
1089             fillAugmentTarget(augmentBuilder, lb);
1090             ((AugmentationTargetBuilder) lb).addAugmentation(augmentBuilder);
1091             SchemaPath oldPath = lb.getPath();
1092             lb.rebuild();
1093             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1094             augmentBuilder.setResolved(true);
1095             module.augmentResolved();
1096         } else if (node instanceof ChoiceNodeImpl) {
1097             ChoiceNodeImpl ch = (ChoiceNodeImpl) node;
1098             ChoiceBuilder chb = ch.toBuilder();
1099             fillAugmentTarget(augmentBuilder, chb);
1100             ((AugmentationTargetBuilder) chb).addAugmentation(augmentBuilder);
1101             SchemaPath oldPath = chb.getPath();
1102             chb.rebuild();
1103             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1104             augmentBuilder.setResolved(true);
1105             module.augmentResolved();
1106         } else if (node instanceof ChoiceCaseNodeImpl) {
1107             ChoiceCaseNodeImpl chc = (ChoiceCaseNodeImpl) node;
1108             ChoiceCaseBuilder chcb = chc.toBuilder();
1109             fillAugmentTarget(augmentBuilder, chcb);
1110             ((AugmentationTargetBuilder) chcb).addAugmentation(augmentBuilder);
1111             SchemaPath oldPath = chcb.getPath();
1112             chcb.rebuild();
1113             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1114             augmentBuilder.setResolved(true);
1115             module.augmentResolved();
1116         } else if (node instanceof NotificationDefinitionImpl) {
1117             NotificationDefinitionImpl nd = (NotificationDefinitionImpl) node;
1118             NotificationBuilder nb = nd.toBuilder();
1119             fillAugmentTarget(augmentBuilder, nb);
1120             ((AugmentationTargetBuilder) nb).addAugmentation(augmentBuilder);
1121             SchemaPath oldPath = nb.getPath();
1122             nb.rebuild();
1123             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1124             augmentBuilder.setResolved(true);
1125             module.augmentResolved();
1126         } else {
1127             throw new YangParseException(module.getName(), line, "Target of type " + node.getClass()
1128                     + " can not be augmented.");
1129         }
1130     }
1131
1132     public static void processAugmentation(final AugmentationSchemaBuilder augmentBuilder, final List<QName> path,
1133             final ModuleBuilder module, final QName qname, final ModuleBuilder dependentModuleBuilder) {
1134         DataSchemaNodeBuilder currentParent = null;
1135         for (DataSchemaNodeBuilder child : dependentModuleBuilder.getChildNodes()) {
1136             final QName childQName = child.getQName();
1137             if (childQName.getLocalName().equals(qname.getLocalName())) {
1138                 currentParent = child;
1139                 break;
1140             }
1141         }
1142
1143         if (currentParent == null) {
1144             return;
1145         }
1146
1147         for (int i = 1; i < path.size(); i++) {
1148             final QName currentQName = path.get(i);
1149             DataSchemaNodeBuilder newParent = null;
1150             for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent).getChildNodes()) {
1151                 final QName childQName = child.getQName();
1152                 if (childQName.getLocalName().equals(currentQName.getLocalName())) {
1153                     newParent = child;
1154                     break;
1155                 }
1156             }
1157             if (newParent == null) {
1158                 break; // node not found, quit search
1159             } else {
1160                 currentParent = newParent;
1161             }
1162         }
1163
1164         final String currentName = currentParent.getQName().getLocalName();
1165         final String lastAugmentPathElementName = path.get(path.size() - 1).getLocalName();
1166         if (currentName.equals(lastAugmentPathElementName)) {
1167
1168             if (currentParent instanceof ChoiceBuilder) {
1169                 fillAugmentTarget(augmentBuilder, (ChoiceBuilder) currentParent);
1170             } else {
1171                 fillAugmentTarget(augmentBuilder, (DataNodeContainerBuilder) currentParent);
1172             }
1173             ((AugmentationTargetBuilder) currentParent).addAugmentation(augmentBuilder);
1174             SchemaPath oldPath = currentParent.getPath();
1175             augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1176             augmentBuilder.setResolved(true);
1177             module.augmentResolved();
1178         }
1179     }
1180
1181     /**
1182      * Create new type builder based on old type with new base type.
1183      *
1184      * @param newBaseType
1185      *            new base type builder
1186      * @param oldExtendedType
1187      *            old type
1188      * @param modules
1189      *            all loaded modules
1190      * @param module
1191      *            current module
1192      * @param line
1193      *            current line in module
1194      * @return new type builder based on old type with new base type
1195      */
1196     public static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
1197             final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1198             final ModuleBuilder module, final int line) {
1199         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
1200         tc.addFractionDigits(oldExtendedType.getFractionDigits());
1201         tc.addLengths(oldExtendedType.getLengths());
1202         tc.addPatterns(oldExtendedType.getPatterns());
1203         tc.addRanges(oldExtendedType.getRanges());
1204
1205         final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
1206         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(oldExtendedType.getQName(), line);
1207         newType.setTypedef(newBaseType);
1208         newType.setPath(oldExtendedType.getPath());
1209         newType.setDescription(oldExtendedType.getDescription());
1210         newType.setReference(oldExtendedType.getReference());
1211         newType.setStatus(oldExtendedType.getStatus());
1212         newType.setLengths(constraints.getLength());
1213         newType.setPatterns(constraints.getPatterns());
1214         newType.setRanges(constraints.getRange());
1215         newType.setFractionDigits(constraints.getFractionDigits());
1216         newType.setUnits(oldExtendedType.getUnits());
1217         newType.setDefaultValue(oldExtendedType.getDefaultValue());
1218         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
1219         return newType;
1220     }
1221
1222     /**
1223      * Create new type builder based on old type with new base type.
1224      *
1225      * @param newBaseType
1226      *            new base type
1227      * @param oldExtendedType
1228      *            old type
1229      * @param modules
1230      *            all loaded modules
1231      * @param module
1232      *            current module
1233      * @param line
1234      *            current line in module
1235      * @return new type builder based on old type with new base type
1236      */
1237     public static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
1238             final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
1239         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
1240
1241         final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
1242         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(oldExtendedType.getQName(), line);
1243         newType.setType(newBaseType);
1244         newType.setPath(oldExtendedType.getPath());
1245         newType.setDescription(oldExtendedType.getDescription());
1246         newType.setReference(oldExtendedType.getReference());
1247         newType.setStatus(oldExtendedType.getStatus());
1248         newType.setLengths(constraints.getLength());
1249         newType.setPatterns(constraints.getPatterns());
1250         newType.setRanges(constraints.getRange());
1251         newType.setFractionDigits(constraints.getFractionDigits());
1252         newType.setUnits(oldExtendedType.getUnits());
1253         newType.setDefaultValue(oldExtendedType.getDefaultValue());
1254         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
1255         return newType;
1256     }
1257
1258     /**
1259      * Pull restrictions from type and add them to constraints.
1260      *
1261      * @param typeToResolve
1262      *            type from which constraints will be read
1263      * @param constraints
1264      *            constraints object to which constraints will be added
1265      * @return constraints contstraints object containing constraints from given
1266      *         type
1267      */
1268     private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
1269             final TypeConstraints constraints) {
1270         // union type cannot be restricted
1271         if (typeToResolve instanceof UnionTypeDefinition) {
1272             return constraints;
1273         }
1274         if (typeToResolve instanceof ExtendedType) {
1275             ExtendedType extType = (ExtendedType) typeToResolve;
1276             constraints.addFractionDigits(extType.getFractionDigits());
1277             constraints.addLengths(extType.getLengths());
1278             constraints.addPatterns(extType.getPatterns());
1279             constraints.addRanges(extType.getRanges());
1280             return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
1281         } else {
1282             mergeConstraints(typeToResolve, constraints);
1283             return constraints;
1284         }
1285     }
1286
1287     public static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
1288             final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1289             final ModuleBuilder builder, final SchemaContext context) {
1290
1291         // union type cannot be restricted
1292         if (nodeToResolve instanceof UnionTypeBuilder) {
1293             return constraints;
1294         }
1295
1296         if (nodeToResolve instanceof TypeDefinitionBuilder) {
1297             TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
1298             constraints.addFractionDigits(typedefToResolve.getFractionDigits());
1299             constraints.addLengths(typedefToResolve.getLengths());
1300             constraints.addPatterns(typedefToResolve.getPatterns());
1301             constraints.addRanges(typedefToResolve.getRanges());
1302         }
1303
1304         TypeDefinition<?> type = nodeToResolve.getType();
1305         if (type == null) {
1306             return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
1307         } else {
1308             QName qname = type.getQName();
1309             if (type instanceof UnknownType) {
1310                 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder, qname.getPrefix(),
1311                         nodeToResolve.getLine());
1312                 if (dependentModuleBuilder == null) {
1313                     if (context == null) {
1314                         throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
1315                                 "Failed to resolved type constraints.");
1316                     }
1317                     Module dm = findModuleFromContext(context, builder, qname.getPrefix(), nodeToResolve.getLine());
1318                     TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
1319                     if (t instanceof ExtendedType) {
1320                         ExtendedType extType = (ExtendedType) t;
1321                         constraints.addFractionDigits(extType.getFractionDigits());
1322                         constraints.addLengths(extType.getLengths());
1323                         constraints.addPatterns(extType.getPatterns());
1324                         constraints.addRanges(extType.getRanges());
1325                         return constraints;
1326                     } else {
1327                         mergeConstraints(t, constraints);
1328                         return constraints;
1329                     }
1330                 } else {
1331                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve.getPath(),
1332                             dependentModuleBuilder, qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
1333                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
1334                 }
1335             } else if (type instanceof ExtendedType) {
1336                 ExtendedType extType = (ExtendedType) type;
1337                 constraints.addFractionDigits(extType.getFractionDigits());
1338                 constraints.addLengths(extType.getLengths());
1339                 constraints.addPatterns(extType.getPatterns());
1340                 constraints.addRanges(extType.getRanges());
1341
1342                 TypeDefinition<?> base = extType.getBaseType();
1343                 if (base instanceof UnknownType) {
1344                     ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, base.getQName()
1345                             .getPrefix(), nodeToResolve.getLine());
1346                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve.getPath(), dependentModule,
1347                             base.getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
1348                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
1349                 } else {
1350                     // it has to be base yang type
1351                     mergeConstraints(type, constraints);
1352                     return constraints;
1353                 }
1354             } else {
1355                 // it is base yang type
1356                 mergeConstraints(type, constraints);
1357                 return constraints;
1358             }
1359         }
1360     }
1361
1362     /**
1363      * Search for type definition builder by name.
1364      *
1365      * @param dirtyNodeSchemaPath
1366      *            schema path of node which contains unresolved type
1367      * @param dependentModule
1368      *            module which should contains referenced type
1369      * @param typeName
1370      *            name of type definition
1371      * @param currentModuleName
1372      *            name of current module
1373      * @param line
1374      *            current line in yang model
1375      * @return
1376      */
1377     public static TypeDefinitionBuilder findTypeDefinitionBuilder(final SchemaPath dirtyNodeSchemaPath,
1378             final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
1379         final List<QName> path = dirtyNodeSchemaPath.getPath();
1380         TypeDefinitionBuilder result = null;
1381
1382         Set<TypeDefinitionBuilder> typedefs = dependentModule.getModuleTypedefs();
1383         result = findTypedefBuilderByName(typedefs, typeName);
1384
1385         if (result == null) {
1386             Builder currentNode = null;
1387             final List<String> currentPath = new ArrayList<String>();
1388             currentPath.add(dependentModule.getName());
1389
1390             for (int i = 0; i < path.size(); i++) {
1391                 QName qname = path.get(i);
1392                 currentPath.add(qname.getLocalName());
1393                 currentNode = dependentModule.getModuleNode(currentPath);
1394
1395                 if (currentNode instanceof RpcDefinitionBuilder) {
1396                     typedefs = ((RpcDefinitionBuilder) currentNode).getTypeDefinitions();
1397                 } else if (currentNode instanceof DataNodeContainerBuilder) {
1398                     typedefs = ((DataNodeContainerBuilder) currentNode).getTypeDefinitions();
1399                 } else {
1400                     typedefs = Collections.emptySet();
1401                 }
1402
1403                 result = findTypedefBuilderByName(typedefs, typeName);
1404                 if (result != null) {
1405                     break;
1406                 }
1407             }
1408         }
1409
1410         if (result != null) {
1411             return result;
1412         }
1413         throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");
1414     }
1415
1416 }