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