69020cbff704d1f61763412cfc9d4b6167bc1f86
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / TypeUtils.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 static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11
12 import java.util.ArrayList;
13 import java.util.Date;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.TreeMap;
18
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.Module;
21 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
22 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
23 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
24 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
25 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
26 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
28 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
29 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
30 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
31 import org.opendaylight.yangtools.yang.model.util.Int16;
32 import org.opendaylight.yangtools.yang.model.util.Int32;
33 import org.opendaylight.yangtools.yang.model.util.Int64;
34 import org.opendaylight.yangtools.yang.model.util.Int8;
35 import org.opendaylight.yangtools.yang.model.util.StringType;
36 import org.opendaylight.yangtools.yang.model.util.Uint16;
37 import org.opendaylight.yangtools.yang.model.util.Uint32;
38 import org.opendaylight.yangtools.yang.model.util.Uint64;
39 import org.opendaylight.yangtools.yang.model.util.Uint8;
40 import org.opendaylight.yangtools.yang.model.util.UnknownType;
41 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
49 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
50
51 /**
52  * Utility class which contains helper methods for dealing with type operations.
53  */
54 public class TypeUtils {
55
56     private TypeUtils() {
57     }
58
59     /**
60      * Resolve unknown type of node. It is assumed that type of node is either
61      * UnknownType or ExtendedType with UnknownType as base type.
62      *
63      * @param nodeToResolve
64      *            node with type to resolve
65      * @param modules
66      *            all loaded modules
67      * @param module
68      *            current module
69      */
70     public static void resolveType(final TypeAwareBuilder nodeToResolve,
71             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
72         TypeDefinitionBuilder resolvedType = null;
73         final int line = nodeToResolve.getLine();
74         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
75         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
76         final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, unknownTypeQName.getPrefix(),
77                 line);
78
79         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve, dependentModule,
80                 unknownTypeQName.getLocalName(), module.getName(), line);
81
82         if (nodeToResolveType instanceof ExtendedType) {
83             final ExtendedType extType = (ExtendedType) nodeToResolveType;
84             final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
85                     modules, module, nodeToResolve.getLine());
86             resolvedType = newType;
87         } else {
88             resolvedType = targetTypeBuilder;
89         }
90
91         // validate constraints
92         final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve,
93                 new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, null);
94         constraints.validateConstraints();
95
96         nodeToResolve.setTypedef(resolvedType);
97     }
98
99     /**
100      * Resolve unknown type of node. It is assumed that type of node is either
101      * UnknownType or ExtendedType with UnknownType as base type.
102      *
103      * @param nodeToResolve
104      *            node with type to resolve
105      * @param modules
106      *            all loaded modules
107      * @param module
108      *            current module
109      * @param context
110      *            SchemaContext containing already resolved modules
111      */
112     public static void resolveTypeWithContext(final TypeAwareBuilder nodeToResolve,
113             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
114             final SchemaContext context) {
115         TypeDefinitionBuilder resolvedType = null;
116         final int line = nodeToResolve.getLine();
117         final TypeDefinition<?> nodeToResolveType = nodeToResolve.getType();
118         final QName unknownTypeQName = nodeToResolveType.getBaseType().getQName();
119         final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
120                 unknownTypeQName.getPrefix(), line);
121
122         if (dependentModuleBuilder == null) {
123             final Module dependentModule = findModuleFromContext(context, module, unknownTypeQName.getPrefix(), line);
124             final Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
125             final TypeDefinition<?> type = findTypeByName(types, unknownTypeQName.getLocalName());
126
127             if (nodeToResolveType instanceof ExtendedType) {
128                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
129                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, module,
130                         nodeToResolve.getLine());
131
132                 nodeToResolve.setTypedef(newType);
133             } else {
134                 if (nodeToResolve instanceof TypeDefinitionBuilder) {
135                     TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
136                     TypeConstraints tc = findConstraintsFromTypeBuilder(nodeToResolve,
137                             new TypeConstraints(module.getName(), nodeToResolve.getLine()), modules, module, context);
138                     tdb.setLengths(tc.getLength());
139                     tdb.setPatterns(tc.getPatterns());
140                     tdb.setRanges(tc.getRange());
141                     tdb.setFractionDigits(tc.getFractionDigits());
142                 }
143                 nodeToResolve.setType(type);
144             }
145
146         } else {
147             final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(nodeToResolve,
148                     dependentModuleBuilder, unknownTypeQName.getLocalName(), module.getName(), line);
149
150             if (nodeToResolveType instanceof ExtendedType) {
151                 final ExtendedType extType = (ExtendedType) nodeToResolveType;
152                 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder, extType,
153                         modules, module, nodeToResolve.getLine());
154                 resolvedType = newType;
155             } else {
156                 resolvedType = targetTypeBuilder;
157             }
158
159             // validate constraints
160             final TypeConstraints constraints = findConstraintsFromTypeBuilder(nodeToResolve, new TypeConstraints(
161                     module.getName(), nodeToResolve.getLine()), modules, module, context);
162             constraints.validateConstraints();
163
164             nodeToResolve.setTypedef(resolvedType);
165         }
166     }
167
168     public static void resolveTypeUnion(final UnionTypeBuilder union,
169             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
170
171         final List<TypeDefinition<?>> unionTypes = union.getTypes();
172         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
173         for (TypeDefinition<?> unionType : unionTypes) {
174             if (unionType instanceof UnknownType) {
175                 final UnknownType ut = (UnknownType) unionType;
176                 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
177                         .getPrefix(), union.getLine());
178                 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModule, ut
179                         .getQName().getLocalName(), builder.getName(), union.getLine());
180                 union.setTypedef(resolvedType);
181                 toRemove.add(ut);
182             } else if (unionType instanceof ExtendedType) {
183                 final ExtendedType extType = (ExtendedType) unionType;
184                 final TypeDefinition<?> extTypeBase = extType.getBaseType();
185                 if (extTypeBase instanceof UnknownType) {
186                     final UnknownType ut = (UnknownType) extTypeBase;
187                     final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, builder, ut.getQName()
188                             .getPrefix(), union.getLine());
189                     final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union, dependentModule,
190                             ut.getQName().getLocalName(), builder.getName(), union.getLine());
191
192                     final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
193                             extType, modules, builder, union.getLine());
194
195                     union.setTypedef(newType);
196                     toRemove.add(extType);
197                 }
198             }
199         }
200         unionTypes.removeAll(toRemove);
201     }
202
203     public static void resolveTypeUnionWithContext(final UnionTypeBuilder union,
204             final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder,
205             final SchemaContext context) {
206
207         final List<TypeDefinition<?>> unionTypes = union.getTypes();
208         final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
209         for (TypeDefinition<?> unionType : unionTypes) {
210             if (unionType instanceof UnknownType) {
211                 final UnknownType ut = (UnknownType) unionType;
212                 final QName utQName = ut.getQName();
213                 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
214                         utQName.getPrefix(), union.getLine());
215
216                 if (dependentModuleBuilder == null) {
217                     Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
218                             union.getLine());
219                     Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
220                     TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
221                     union.setType(type);
222                     toRemove.add(ut);
223                 } else {
224                     final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(union, dependentModuleBuilder,
225                             utQName.getLocalName(), builder.getName(), union.getLine());
226                     union.setTypedef(resolvedType);
227                     toRemove.add(ut);
228                 }
229
230             } else if (unionType instanceof ExtendedType) {
231                 final ExtendedType extType = (ExtendedType) unionType;
232                 TypeDefinition<?> extTypeBase = extType.getBaseType();
233                 if (extTypeBase instanceof UnknownType) {
234                     final UnknownType ut = (UnknownType) extTypeBase;
235                     final QName utQName = ut.getQName();
236                     final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, builder,
237                             utQName.getPrefix(), union.getLine());
238
239                     if (dependentModuleBuilder == null) {
240                         final Module dependentModule = findModuleFromContext(context, builder, utQName.getPrefix(),
241                                 union.getLine());
242                         Set<TypeDefinition<?>> types = dependentModule.getTypeDefinitions();
243                         TypeDefinition<?> type = findTypeByName(types, utQName.getLocalName());
244                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(type, extType, builder, 0);
245
246                         union.setTypedef(newType);
247                         toRemove.add(extType);
248                     } else {
249                         final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(union,
250                                 dependentModuleBuilder, utQName.getLocalName(), builder.getName(), union.getLine());
251
252                         final TypeDefinitionBuilder newType = extendedTypeWithNewBaseTypeBuilder(targetTypeBuilder,
253                                 extType, modules, builder, union.getLine());
254
255                         union.setTypedef(newType);
256                         toRemove.add(extType);
257                     }
258                 }
259             }
260         }
261         unionTypes.removeAll(toRemove);
262     }
263
264     /**
265      * Search types for type with given name.
266      *
267      * @param types
268      *            types to search
269      * @param name
270      *            name of type
271      * @return type with given name if present in collection, null otherwise
272      */
273     private static TypeDefinitionBuilder findTypedefBuilderByName(Set<TypeDefinitionBuilder> types, String name) {
274         for (TypeDefinitionBuilder td : types) {
275             if (td.getQName().getLocalName().equals(name)) {
276                 return td;
277             }
278         }
279         return null;
280     }
281
282     /**
283      * Find type by name.
284      *
285      * @param types
286      *            collection of types
287      * @param typeName
288      *            type name
289      * @return type with given name if it is present in collection, null
290      *         otherwise
291      */
292     private static TypeDefinition<?> findTypeByName(Set<TypeDefinition<?>> types, String typeName) {
293         for (TypeDefinition<?> type : types) {
294             if (type.getQName().getLocalName().equals(typeName)) {
295                 return type;
296             }
297         }
298         return null;
299     }
300
301     /**
302      * Pull restriction from type and add them to constraints.
303      *
304      * @param type
305      * @param constraints
306      */
307     private static void mergeConstraints(final TypeDefinition<?> type, final TypeConstraints constraints) {
308         if (type instanceof DecimalTypeDefinition) {
309             constraints.addRanges(((DecimalTypeDefinition) type).getRangeStatements());
310             constraints.addFractionDigits(((DecimalTypeDefinition) type).getFractionDigits());
311         } else if (type instanceof IntegerTypeDefinition) {
312             constraints.addRanges(((IntegerTypeDefinition) type).getRangeStatements());
313         } else if (type instanceof StringTypeDefinition) {
314             constraints.addPatterns(((StringTypeDefinition) type).getPatterns());
315             constraints.addLengths(((StringTypeDefinition) type).getLengthStatements());
316         } else if (type instanceof BinaryTypeDefinition) {
317             constraints.addLengths(((BinaryTypeDefinition) type).getLengthConstraints());
318         }
319     }
320
321     /**
322      * Create new ExtendedType based on given type and with schema path.
323      *
324      * @param newPath
325      *            schema path for new type
326      * @param oldType
327      *            type based
328      * @return
329      */
330     static ExtendedType createNewExtendedType(final ExtendedType oldType, final SchemaPath newPath) {
331         QName qname = oldType.getQName();
332         TypeDefinition<?> baseType = oldType.getBaseType();
333         String desc = oldType.getDescription();
334         String ref = oldType.getReference();
335         ExtendedType.Builder builder = new ExtendedType.Builder(qname, baseType, desc, ref, newPath);
336         builder.status(oldType.getStatus());
337         builder.lengths(oldType.getLengths());
338         builder.patterns(oldType.getPatterns());
339         builder.ranges(oldType.getRanges());
340         builder.fractionDigits(oldType.getFractionDigits());
341         builder.unknownSchemaNodes(oldType.getUnknownSchemaNodes());
342         return builder.build();
343     }
344
345     static StringTypeDefinition createNewStringType(final SchemaPath schemaPath, final QName nodeQName,
346             final StringTypeDefinition nodeType) {
347         final List<QName> path = schemaPath.getPath();
348         final List<QName> newPath = new ArrayList<QName>(path);
349         newPath.add(nodeQName);
350         newPath.add(nodeType.getQName());
351         final SchemaPath newSchemaPath = new SchemaPath(newPath, schemaPath.isAbsolute());
352         return new StringType(newSchemaPath);
353     }
354
355     static IntegerTypeDefinition createNewIntType(final SchemaPath schemaPath, final QName nodeQName,
356             final IntegerTypeDefinition type) {
357         final QName typeQName = type.getQName();
358         final SchemaPath newSchemaPath = createSchemaPath(schemaPath, nodeQName, typeQName);
359         final String localName = typeQName.getLocalName();
360
361         if ("int8".equals(localName)) {
362             return new Int8(newSchemaPath);
363         } else if ("int16".equals(localName)) {
364             return new Int16(newSchemaPath);
365         } else if ("int32".equals(localName)) {
366             return new Int32(newSchemaPath);
367         } else if ("int64".equals(localName)) {
368             return new Int64(newSchemaPath);
369         } else {
370             return null;
371         }
372     }
373
374     static UnsignedIntegerTypeDefinition createNewUintType(final SchemaPath schemaPath, final QName nodeQName,
375             final UnsignedIntegerTypeDefinition type) {
376         final QName typeQName = type.getQName();
377         final SchemaPath newSchemaPath = createSchemaPath(schemaPath, nodeQName, typeQName);
378         final String localName = typeQName.getLocalName();
379
380         if ("uint8".equals(localName)) {
381             return new Uint8(newSchemaPath);
382         } else if ("uint16".equals(localName)) {
383             return new Uint16(newSchemaPath);
384         } else if ("uint32".equals(localName)) {
385             return new Uint32(newSchemaPath);
386         } else if ("uint64".equals(localName)) {
387             return new Uint64(newSchemaPath);
388         } else {
389             return null;
390         }
391     }
392
393     /**
394      * Create new type builder based on old type with new base type.
395      *
396      * @param newBaseType
397      *            new base type builder
398      * @param oldExtendedType
399      *            old type
400      * @param modules
401      *            all loaded modules
402      * @param module
403      *            current module
404      * @param line
405      *            current line in module
406      * @return new type builder based on old type with new base type
407      */
408     private static TypeDefinitionBuilder extendedTypeWithNewBaseTypeBuilder(final TypeDefinitionBuilder newBaseType,
409             final ExtendedType oldExtendedType, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
410             final ModuleBuilder module, final int line) {
411         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
412         tc.addFractionDigits(oldExtendedType.getFractionDigits());
413         tc.addLengths(oldExtendedType.getLengths());
414         tc.addPatterns(oldExtendedType.getPatterns());
415         tc.addRanges(oldExtendedType.getRanges());
416
417         final TypeConstraints constraints = findConstraintsFromTypeBuilder(newBaseType, tc, modules, module, null);
418         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
419                 oldExtendedType.getQName());
420         newType.setTypedef(newBaseType);
421         newType.setPath(oldExtendedType.getPath());
422         newType.setDescription(oldExtendedType.getDescription());
423         newType.setReference(oldExtendedType.getReference());
424         newType.setStatus(oldExtendedType.getStatus());
425         newType.setLengths(constraints.getLength());
426         newType.setPatterns(constraints.getPatterns());
427         newType.setRanges(constraints.getRange());
428         newType.setFractionDigits(constraints.getFractionDigits());
429         newType.setUnits(oldExtendedType.getUnits());
430         newType.setDefaultValue(oldExtendedType.getDefaultValue());
431         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
432         return newType;
433     }
434
435     /**
436      * Create new type builder based on old type with new base type.
437      *
438      * @param newBaseType
439      *            new base type
440      * @param oldExtendedType
441      *            old type
442      * @param modules
443      *            all loaded modules
444      * @param module
445      *            current module
446      * @param line
447      *            current line in module
448      * @return new type builder based on old type with new base type
449      */
450     private static TypeDefinitionBuilder extendedTypeWithNewBaseType(final TypeDefinition<?> newBaseType,
451             final ExtendedType oldExtendedType, final ModuleBuilder module, final int line) {
452         final TypeConstraints tc = new TypeConstraints(module.getName(), line);
453
454         final TypeConstraints constraints = findConstraintsFromTypeDefinition(newBaseType, tc);
455         final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(module.getModuleName(), line,
456                 oldExtendedType.getQName());
457         newType.setType(newBaseType);
458         newType.setPath(oldExtendedType.getPath());
459         newType.setDescription(oldExtendedType.getDescription());
460         newType.setReference(oldExtendedType.getReference());
461         newType.setStatus(oldExtendedType.getStatus());
462         newType.setLengths(constraints.getLength());
463         newType.setPatterns(constraints.getPatterns());
464         newType.setRanges(constraints.getRange());
465         newType.setFractionDigits(constraints.getFractionDigits());
466         newType.setUnits(oldExtendedType.getUnits());
467         newType.setDefaultValue(oldExtendedType.getDefaultValue());
468         newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
469         return newType;
470     }
471
472     /**
473      * Pull restrictions from type and add them to constraints.
474      *
475      * @param typeToResolve
476      *            type from which constraints will be read
477      * @param constraints
478      *            constraints object to which constraints will be added
479      * @return constraints contstraints object containing constraints from given
480      *         type
481      */
482     private static TypeConstraints findConstraintsFromTypeDefinition(final TypeDefinition<?> typeToResolve,
483             final TypeConstraints constraints) {
484         // union type cannot be restricted
485         if (typeToResolve instanceof UnionTypeDefinition) {
486             return constraints;
487         }
488         if (typeToResolve instanceof ExtendedType) {
489             ExtendedType extType = (ExtendedType) typeToResolve;
490             constraints.addFractionDigits(extType.getFractionDigits());
491             constraints.addLengths(extType.getLengths());
492             constraints.addPatterns(extType.getPatterns());
493             constraints.addRanges(extType.getRanges());
494             return findConstraintsFromTypeDefinition(extType.getBaseType(), constraints);
495         } else {
496             mergeConstraints(typeToResolve, constraints);
497             return constraints;
498         }
499     }
500
501     private static TypeConstraints findConstraintsFromTypeBuilder(final TypeAwareBuilder nodeToResolve,
502             final TypeConstraints constraints, final Map<String, TreeMap<Date, ModuleBuilder>> modules,
503             final ModuleBuilder builder, final SchemaContext context) {
504
505         // union and identityref types cannot be restricted
506         if (nodeToResolve instanceof UnionTypeBuilder || nodeToResolve instanceof IdentityrefTypeBuilder) {
507             return constraints;
508         }
509
510         if (nodeToResolve instanceof TypeDefinitionBuilder) {
511             TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
512             constraints.addFractionDigits(typedefToResolve.getFractionDigits());
513             constraints.addLengths(typedefToResolve.getLengths());
514             constraints.addPatterns(typedefToResolve.getPatterns());
515             constraints.addRanges(typedefToResolve.getRanges());
516         }
517
518         TypeDefinition<?> type = nodeToResolve.getType();
519         if (type == null) {
520             return findConstraintsFromTypeBuilder(nodeToResolve.getTypedef(), constraints, modules, builder, context);
521         } else {
522             QName qname = type.getQName();
523             if (type instanceof UnknownType) {
524                 ModuleBuilder dependentModuleBuilder = ParserUtils.findDependentModuleBuilder(modules, builder,
525                         qname.getPrefix(), nodeToResolve.getLine());
526                 if (dependentModuleBuilder == null) {
527                     if (context == null) {
528                         throw new YangParseException(builder.getName(), nodeToResolve.getLine(),
529                                 "Failed to resolved type constraints.");
530                     }
531                     Module dm = ParserUtils.findModuleFromContext(context, builder, qname.getPrefix(),
532                             nodeToResolve.getLine());
533                     TypeDefinition<?> t = findTypeByName(dm.getTypeDefinitions(), qname.getLocalName());
534                     if (t instanceof ExtendedType) {
535                         ExtendedType extType = (ExtendedType) t;
536                         constraints.addFractionDigits(extType.getFractionDigits());
537                         constraints.addLengths(extType.getLengths());
538                         constraints.addPatterns(extType.getPatterns());
539                         constraints.addRanges(extType.getRanges());
540                         return constraints;
541                     } else {
542                         mergeConstraints(t, constraints);
543                         return constraints;
544                     }
545                 } else {
546                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModuleBuilder,
547                             qname.getLocalName(), builder.getName(), nodeToResolve.getLine());
548                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModuleBuilder, context);
549                 }
550             } else if (type instanceof ExtendedType) {
551                 ExtendedType extType = (ExtendedType) type;
552                 constraints.addFractionDigits(extType.getFractionDigits());
553                 constraints.addLengths(extType.getLengths());
554                 constraints.addPatterns(extType.getPatterns());
555                 constraints.addRanges(extType.getRanges());
556
557                 TypeDefinition<?> base = extType.getBaseType();
558                 if (base instanceof UnknownType) {
559                     ModuleBuilder dependentModule = ParserUtils.findDependentModuleBuilder(modules, builder, base
560                             .getQName().getPrefix(), nodeToResolve.getLine());
561                     TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(nodeToResolve, dependentModule, base
562                             .getQName().getLocalName(), builder.getName(), nodeToResolve.getLine());
563                     return findConstraintsFromTypeBuilder(tdb, constraints, modules, dependentModule, context);
564                 } else {
565                     // it has to be base yang type
566                     mergeConstraints(type, constraints);
567                     return constraints;
568                 }
569             } else {
570                 // it is base yang type
571                 mergeConstraints(type, constraints);
572                 return constraints;
573             }
574         }
575     }
576
577     /**
578      * Search for type definition builder by name.
579      *
580      * @param dirtyNodeSchemaPath
581      *            schema path of node which contains unresolved type
582      * @param dependentModule
583      *            module which should contains referenced type
584      * @param typeName
585      *            name of type definition
586      * @param currentModuleName
587      *            name of current module
588      * @param line
589      *            current line in module
590      * @return
591      */
592     private static TypeDefinitionBuilder findTypeDefinitionBuilder(final TypeAwareBuilder nodeToResolve,
593             final ModuleBuilder dependentModule, final String typeName, final String currentModuleName, final int line) {
594
595         TypeDefinitionBuilder result = null;
596
597         Set<TypeDefinitionBuilder> typedefs = dependentModule.getTypeDefinitionBuilders();
598         result = findTypedefBuilderByName(typedefs, typeName);
599         if (result != null) {
600             return result;
601         }
602
603         Builder parent = nodeToResolve.getParent();
604         while (parent != null) {
605             if (parent instanceof DataNodeContainerBuilder) {
606                 typedefs = ((DataNodeContainerBuilder) parent).getTypeDefinitionBuilders();
607             } else if (parent instanceof RpcDefinitionBuilder) {
608                 typedefs = ((RpcDefinitionBuilder) parent).getTypeDefinitions();
609             }
610             result = findTypedefBuilderByName(typedefs, typeName);
611             if (result == null) {
612                 parent = parent.getParent();
613             } else {
614                 break;
615             }
616         }
617
618         if (result == null) {
619             throw new YangParseException(currentModuleName, line, "Referenced type '" + typeName + "' not found.");
620         }
621         return result;
622     }
623
624 }