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