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