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