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