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