Custom Node Type jaxb string to id
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / impl / YangParserImpl.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.impl;
9
10 import java.io.File;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.NoSuchElementException;
26 import java.util.Set;
27 import java.util.TreeMap;
28
29 import org.antlr.v4.runtime.ANTLRInputStream;
30 import org.antlr.v4.runtime.CommonTokenStream;
31 import org.antlr.v4.runtime.tree.ParseTree;
32 import org.antlr.v4.runtime.tree.ParseTreeWalker;
33 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
35 import org.opendaylight.controller.yang.common.QName;
36 import org.opendaylight.controller.yang.model.api.Module;
37 import org.opendaylight.controller.yang.model.api.ModuleImport;
38 import org.opendaylight.controller.yang.model.api.SchemaContext;
39 import org.opendaylight.controller.yang.model.api.SchemaPath;
40 import org.opendaylight.controller.yang.model.api.TypeDefinition;
41 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
42 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
45 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
46 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
47 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
48 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
49 import org.opendaylight.controller.yang.model.util.ExtendedType;
50 import org.opendaylight.controller.yang.model.util.IdentityrefType;
51 import org.opendaylight.controller.yang.model.util.UnknownType;
52 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
53 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
54 import org.opendaylight.controller.yang.parser.builder.api.Builder;
55 import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
56 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
57 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
58 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
61 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
63 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
64 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
65 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
66 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
74 import org.opendaylight.controller.yang.parser.util.ParserUtils;
75 import org.opendaylight.controller.yang.parser.util.RefineHolder;
76 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
77 import org.opendaylight.controller.yang.parser.util.YangParseException;
78 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 public final class YangParserImpl implements YangModelParser {
83
84     private static final Logger logger = LoggerFactory
85             .getLogger(YangParserImpl.class);
86
87     @Override
88     public Set<Module> parseYangModels(final List<File> yangFiles) {
89         if (yangFiles != null) {
90             final List<InputStream> inputStreams = new ArrayList<InputStream>();
91
92             for (final File yangFile : yangFiles) {
93                 try {
94                     inputStreams.add(new FileInputStream(yangFile));
95                 } catch (FileNotFoundException e) {
96                     logger.warn("Exception while reading yang file: "
97                             + yangFile.getName(), e);
98                 }
99             }
100             final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
101             return build(modules);
102         }
103         return Collections.emptySet();
104     }
105
106     @Override
107     public Set<Module> parseYangModelsFromStreams(
108             final List<InputStream> yangModelStreams) {
109         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
110         return build(modules);
111     }
112
113     @Override
114     public SchemaContext resolveSchemaContext(final Set<Module> modules) {
115         return new SchemaContextImpl(modules);
116     }
117
118     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
119             final List<InputStream> yangFileStreams) {
120         // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
121         // of items stored in map.
122         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
123         final ParseTreeWalker walker = new ParseTreeWalker();
124         final List<ParseTree> trees = parseStreams(yangFileStreams);
125         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
126
127         // validate yang
128         new YangModelBasicValidator(walker).validate(trees);
129
130         YangParserListenerImpl yangModelParser = null;
131         for (int i = 0; i < trees.size(); i++) {
132             yangModelParser = new YangParserListenerImpl();
133             walker.walk(yangModelParser, trees.get(i));
134             builders[i] = yangModelParser.getModuleBuilder();
135         }
136
137         // module dependency graph sorted
138         List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
139
140         for (ModuleBuilder builder : sorted) {
141             final String builderName = builder.getName();
142             Date builderRevision = builder.getRevision();
143             if (builderRevision == null) {
144                 builderRevision = new Date(0L);
145             }
146             TreeMap<Date, ModuleBuilder> builderByRevision = modules
147                     .get(builderName);
148             if (builderByRevision == null) {
149                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
150             }
151             builderByRevision.put(builderRevision, builder);
152             modules.put(builderName, builderByRevision);
153         }
154         return modules;
155     }
156
157     private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
158         final List<ParseTree> trees = new ArrayList<ParseTree>();
159         for (InputStream yangStream : yangStreams) {
160             trees.add(parseStream(yangStream));
161         }
162         return trees;
163     }
164
165     private ParseTree parseStream(final InputStream yangStream) {
166         ParseTree result = null;
167         try {
168             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
169             final YangLexer lexer = new YangLexer(input);
170             final CommonTokenStream tokens = new CommonTokenStream(lexer);
171             final YangParser parser = new YangParser(tokens);
172             result = parser.yang();
173         } catch (IOException e) {
174             logger.warn("Exception while reading yang file: " + yangStream, e);
175         }
176         return result;
177     }
178
179     private Set<Module> build(
180             final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
181         // fix unresolved nodes
182         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
183                 .entrySet()) {
184             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
185                     .entrySet()) {
186                 final ModuleBuilder moduleBuilder = childEntry.getValue();
187                 fixUnresolvedNodes(modules, moduleBuilder);
188             }
189         }
190         resolveAugments(modules);
191
192         // build
193         // Linked Hash Set MUST be used otherwise the Set will not maintain
194         // order!
195         // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html
196         final Set<Module> result = new LinkedHashSet<Module>();
197         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
198                 .entrySet()) {
199             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
200             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
201                     .entrySet()) {
202                 final ModuleBuilder moduleBuilder = childEntry.getValue();
203                 final Module module = moduleBuilder.build();
204                 modulesByRevision.put(childEntry.getKey(), module);
205                 result.add(module);
206             }
207         }
208         return result;
209     }
210
211     private void fixUnresolvedNodes(
212             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
213             final ModuleBuilder builder) {
214         resolveDirtyNodes(modules, builder);
215         resolveIdentities(modules, builder);
216         resolveUses(modules, builder);
217         resolveUnknownNodes(modules, builder);
218     }
219
220     /**
221      * Search for dirty nodes (node which contains UnknownType) and resolve
222      * unknown types.
223      *
224      * @param modules
225      *            all available modules
226      * @param module
227      *            current module
228      */
229     private void resolveDirtyNodes(
230             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
231             final ModuleBuilder module) {
232         final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
233                 .getDirtyNodes();
234         if (!dirtyNodes.isEmpty()) {
235             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
236                     .entrySet()) {
237
238                 final TypeAwareBuilder nodeToResolve = entry.getValue();
239                 // different handling for union types
240                 if (nodeToResolve instanceof UnionTypeBuilder) {
241                     final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
242                     final List<TypeDefinition<?>> unionTypes = union.getTypes();
243                     final List<UnknownType> toRemove = new ArrayList<UnknownType>();
244                     for (TypeDefinition<?> td : unionTypes) {
245                         if (td instanceof UnknownType) {
246                             final UnknownType unknownType = (UnknownType) td;
247                             final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
248                                     nodeToResolve, unknownType, modules, module);
249                             union.setType(resolvedType);
250                             toRemove.add(unknownType);
251                         }
252                     }
253                     unionTypes.removeAll(toRemove);
254                 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
255                     IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
256                             .getTypedef();
257                     nodeToResolve.setType(new IdentityrefType(findFullQName(
258                             modules, module, idref), idref.getPath()));
259                 } else {
260                     final TypeDefinitionBuilder resolvedType = resolveType(
261                             nodeToResolve, modules, module);
262                     nodeToResolve.setType(resolvedType);
263                 }
264             }
265         }
266     }
267
268     private TypeDefinitionBuilder resolveType(
269             final TypeAwareBuilder typeToResolve,
270             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
271             final ModuleBuilder builder) {
272         final TypeConstraints constraints = new TypeConstraints();
273
274         final TypeDefinitionBuilder targetType = getTypedefBuilder(
275                 typeToResolve, modules, builder);
276         final TypeConstraints tConstraints = findConstraints(typeToResolve,
277                 constraints, modules, builder);
278         targetType.setRanges(tConstraints.getRange());
279         targetType.setLengths(tConstraints.getLength());
280         targetType.setPatterns(tConstraints.getPatterns());
281         targetType.setFractionDigits(tConstraints.getFractionDigits());
282
283         return targetType;
284     }
285
286     private TypeDefinitionBuilder resolveTypeUnion(
287             final TypeAwareBuilder typeToResolve,
288             final UnknownType unknownType,
289             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
290             final ModuleBuilder builder) {
291         final TypeConstraints constraints = new TypeConstraints();
292
293         final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
294                 unknownType, modules, builder);
295         final TypeConstraints tConstraints = findConstraints(typeToResolve,
296                 constraints, modules, builder);
297         targetType.setRanges(tConstraints.getRange());
298         targetType.setLengths(tConstraints.getLength());
299         targetType.setPatterns(tConstraints.getPatterns());
300         targetType.setFractionDigits(tConstraints.getFractionDigits());
301
302         return targetType;
303     }
304
305     private TypeDefinitionBuilder getTypedefBuilder(
306             final TypeAwareBuilder nodeToResolve,
307             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
308             final ModuleBuilder builder) {
309
310         final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
311         if (nodeToResolveBase != null
312                 && !(nodeToResolveBase instanceof UnknownType)) {
313             return (TypeDefinitionBuilder) nodeToResolve;
314         }
315
316         final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
317         final QName unknownTypeQName = unknownType.getQName();
318
319         // search for module which contains referenced typedef
320         final ModuleBuilder dependentModule = findDependentModule(modules,
321                 builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
322         final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
323                 dependentModule, unknownTypeQName.getLocalName(),
324                 builder.getName(), nodeToResolve.getLine());
325
326         final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
327                 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
328         final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
329                 lookedUpBuilderCopy, modules, dependentModule);
330         return resolvedCopy;
331     }
332
333     private TypeDefinitionBuilder getUnionBuilder(
334             final TypeAwareBuilder nodeToResolve,
335             final UnknownType unknownType,
336             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
337             final ModuleBuilder module) {
338
339         final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
340         if (baseTypeToResolve != null
341                 && !(baseTypeToResolve instanceof UnknownType)) {
342             return (TypeDefinitionBuilder) nodeToResolve;
343         }
344
345         final QName unknownTypeQName = unknownType.getQName();
346         // search for module which contains referenced typedef
347         final ModuleBuilder dependentModule = findDependentModule(modules,
348                 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
349         final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
350                 dependentModule, unknownTypeQName.getLocalName(),
351                 module.getName(), nodeToResolve.getLine());
352
353         final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
354                 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
355         final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
356                 lookedUpBuilderCopy, modules, dependentModule);
357         return resolvedCopy;
358     }
359
360     private TypeDefinitionBuilder copyTypedefBuilder(
361             final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
362         if (old instanceof UnionTypeBuilder) {
363             final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
364             final UnionTypeBuilder newUnion = new UnionTypeBuilder(old.getLine());
365             for (TypeDefinition<?> td : oldUnion.getTypes()) {
366                 newUnion.setType(td);
367             }
368             for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
369                 newUnion.setType(copyTypedefBuilder(tdb, true));
370             }
371             newUnion.setPath(old.getPath());
372             return newUnion;
373         }
374
375         final QName oldName = old.getQName();
376         final QName newName = new QName(oldName.getNamespace(),
377                 oldName.getRevision(), oldName.getPrefix(),
378                 oldName.getLocalName());
379         final TypeDefinitionBuilder tdb = new TypedefBuilder(newName,
380                 old.getLine());
381
382         tdb.setRanges(old.getRanges());
383         tdb.setLengths(old.getLengths());
384         tdb.setPatterns(old.getPatterns());
385         tdb.setFractionDigits(old.getFractionDigits());
386         tdb.setPath(old.getPath());
387
388         final TypeDefinition<?> oldType = old.getType();
389         if (oldType == null) {
390             tdb.setType(old.getTypedef());
391         } else {
392             tdb.setType(oldType);
393         }
394
395         if (!seekByTypedefBuilder) {
396             tdb.setDescription(old.getDescription());
397             tdb.setReference(old.getReference());
398             tdb.setStatus(old.getStatus());
399             tdb.setDefaultValue(old.getDefaultValue());
400             tdb.setUnits(old.getUnits());
401         }
402         return tdb;
403     }
404
405     private TypeDefinitionBuilder resolveCopiedBuilder(
406             final TypeDefinitionBuilder copy,
407             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
408             final ModuleBuilder builder) {
409
410         if (copy instanceof UnionTypeBuilder) {
411             final UnionTypeBuilder union = (UnionTypeBuilder) copy;
412             final List<TypeDefinition<?>> unionTypes = union.getTypes();
413             final List<UnknownType> toRemove = new ArrayList<UnknownType>();
414             for (TypeDefinition<?> td : unionTypes) {
415                 if (td instanceof UnknownType) {
416                     final UnknownType unknownType = (UnknownType) td;
417                     final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
418                             union, unknownType, modules, builder);
419                     union.setType(resolvedType);
420                     toRemove.add(unknownType);
421                 }
422             }
423             unionTypes.removeAll(toRemove);
424
425             return union;
426         }
427
428         final TypeDefinition<?> base = copy.getType();
429         final TypeDefinitionBuilder baseTdb = copy.getTypedef();
430         if (base != null && !(base instanceof UnknownType)) {
431             return copy;
432         } else if (base instanceof UnknownType) {
433             final UnknownType unknownType = (UnknownType) base;
434             final QName unknownTypeQName = unknownType.getQName();
435             final String unknownTypePrefix = unknownTypeQName.getPrefix();
436             final ModuleBuilder dependentModule = findDependentModule(modules,
437                     builder, unknownTypePrefix, copy.getLine());
438             final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
439                     modules, dependentModule);
440             copy.setType(utBuilder);
441             return copy;
442         } else if (base == null && baseTdb != null) {
443             // make a copy of baseTypeDef and call again
444             final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
445                     baseTdb, true);
446             final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
447                     baseTdbCopy, modules, builder);
448             copy.setType(baseTdbCopyResolved);
449             return copy;
450         } else {
451             throw new IllegalStateException("Failed to resolve type "
452                     + copy.getQName().getLocalName());
453         }
454     }
455
456     private TypeDefinitionBuilder findTypedefBuilder(
457             final QName unknownTypeQName,
458             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
459             final ModuleBuilder builder, int line) {
460         // search for module which contains referenced typedef
461         final ModuleBuilder dependentModule = findDependentModule(modules,
462                 builder, unknownTypeQName.getPrefix(), line);
463         final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
464                 dependentModule, unknownTypeQName.getLocalName(),
465                 builder.getName(), line);
466         return copyTypedefBuilder(lookedUpBuilder, true);
467     }
468
469     private TypeConstraints findConstraints(
470             final TypeAwareBuilder nodeToResolve,
471             final TypeConstraints constraints,
472             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
473             final ModuleBuilder builder) {
474         // union type cannot be restricted
475         if (nodeToResolve instanceof UnionTypeBuilder) {
476             return constraints;
477         }
478
479         // if referenced type is UnknownType again, search recursively with
480         // current constraints
481         final TypeDefinition<?> referencedType = nodeToResolve.getType();
482         List<RangeConstraint> ranges = Collections.emptyList();
483         List<LengthConstraint> lengths = Collections.emptyList();
484         List<PatternConstraint> patterns = Collections.emptyList();
485         Integer fractionDigits = null;
486         if (referencedType == null) {
487             final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef();
488             ranges = tdb.getRanges();
489             constraints.addRanges(ranges);
490             lengths = tdb.getLengths();
491             constraints.addLengths(lengths);
492             patterns = tdb.getPatterns();
493             constraints.addPatterns(patterns);
494             fractionDigits = tdb.getFractionDigits();
495             constraints.setFractionDigits(fractionDigits);
496             return constraints;
497         } else if (referencedType instanceof ExtendedType) {
498             final ExtendedType ext = (ExtendedType) referencedType;
499             ranges = ext.getRanges();
500             constraints.addRanges(ranges);
501             lengths = ext.getLengths();
502             constraints.addLengths(lengths);
503             patterns = ext.getPatterns();
504             constraints.addPatterns(patterns);
505             fractionDigits = ext.getFractionDigits();
506             constraints.setFractionDigits(fractionDigits);
507             return findConstraints(
508                     findTypedefBuilder(ext.getQName(), modules, builder,
509                             nodeToResolve.getLine()), constraints, modules,
510                     builder);
511         } else if (referencedType instanceof UnknownType) {
512             final UnknownType unknown = (UnknownType) referencedType;
513             ranges = unknown.getRangeStatements();
514             constraints.addRanges(ranges);
515             lengths = unknown.getLengthStatements();
516             constraints.addLengths(lengths);
517             patterns = unknown.getPatterns();
518             constraints.addPatterns(patterns);
519             fractionDigits = unknown.getFractionDigits();
520             constraints.setFractionDigits(fractionDigits);
521
522             String unknownTypePrefix = unknown.getQName().getPrefix();
523             if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
524                 unknownTypePrefix = builder.getPrefix();
525             }
526             final ModuleBuilder dependentModule = findDependentModule(modules,
527                     builder, unknown.getQName().getPrefix(),
528                     nodeToResolve.getLine());
529             final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
530                     unknown.getQName(), modules, builder,
531                     nodeToResolve.getLine());
532             return findConstraints(utBuilder, constraints, modules,
533                     dependentModule);
534         } else {
535             // HANDLE BASE YANG TYPE
536             mergeConstraints(referencedType, constraints);
537             return constraints;
538         }
539     }
540
541     /**
542      * Search for type definition builder by name.
543      *
544      * @param dependentModule
545      *            module to search
546      * @param name
547      *            name of type definition
548      * @param currentModuleName
549      *            current module name
550      * @param line
551      *            current line in yang model
552      * @return
553      */
554     private TypeDefinitionBuilder findTypedefBuilderByName(
555             final ModuleBuilder dependentModule, final String name,
556             final String currentModuleName, final int line) {
557         final Set<TypeDefinitionBuilder> typedefs = dependentModule
558                 .getModuleTypedefs();
559         for (TypeDefinitionBuilder td : typedefs) {
560             if (td.getQName().getLocalName().equals(name)) {
561                 return td;
562             }
563         }
564         throw new YangParseException(currentModuleName, line, "Target module '"
565                 + dependentModule.getName() + "' does not contain typedef '"
566                 + name + "'.");
567     }
568
569     /**
570      * Pull restriction from referenced type and add them to given constraints
571      *
572      * @param referencedType
573      * @param constraints
574      */
575     private void mergeConstraints(final TypeDefinition<?> referencedType,
576             final TypeConstraints constraints) {
577
578         if (referencedType instanceof DecimalTypeDefinition) {
579             constraints.addRanges(((DecimalTypeDefinition) referencedType)
580                     .getRangeStatements());
581             constraints
582                     .setFractionDigits(((DecimalTypeDefinition) referencedType)
583                             .getFractionDigits());
584         } else if (referencedType instanceof IntegerTypeDefinition) {
585             constraints.addRanges(((IntegerTypeDefinition) referencedType)
586                     .getRangeStatements());
587         } else if (referencedType instanceof StringTypeDefinition) {
588             constraints.addPatterns(((StringTypeDefinition) referencedType)
589                     .getPatterns());
590             constraints.addLengths(((StringTypeDefinition) referencedType)
591                     .getLengthStatements());
592         } else if (referencedType instanceof BinaryTypeDefinition) {
593             constraints.addLengths(((BinaryTypeDefinition) referencedType)
594                     .getLengthConstraints());
595         }
596     }
597
598     /**
599      * Go through all augment definitions and resolve them. This method also
600      * finds augment target node and add child nodes to it.
601      *
602      * @param modules
603      *            all available modules
604      */
605     private void resolveAugments(
606             final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
607         final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
608         final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
609         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
610                 .entrySet()) {
611             for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
612                     .entrySet()) {
613                 allModulesList.add(inner.getValue());
614                 allModulesSet.add(inner.getValue());
615             }
616         }
617
618         for (int i = 0; i < allModulesList.size(); i++) {
619             final ModuleBuilder module = allModulesList.get(i);
620             // try to resolve augments in module
621             resolveAugment(modules, module);
622             // while all augments are not resolved
623             final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
624                     .iterator();
625             while (!(module.getAugmentsResolved() == module.getAddedAugments()
626                     .size())) {
627                 ModuleBuilder nextModule = null;
628                 // try resolve other module augments
629                 try {
630                     nextModule = allModulesIterator.next();
631                     resolveAugment(modules, nextModule);
632                 } catch (NoSuchElementException e) {
633                     throw new YangParseException(
634                             "Failed to resolve augments in module '"
635                                     + module.getName() + "'.", e);
636                 }
637                 // then try to resolve first module again
638                 resolveAugment(modules, module);
639             }
640         }
641     }
642
643     /**
644      *
645      * @param modules
646      *            all available modules
647      * @param module
648      *            current module
649      */
650     private void resolveAugment(
651             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
652             final ModuleBuilder module) {
653         if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
654             for (AugmentationSchemaBuilder augmentBuilder : module
655                     .getAddedAugments()) {
656
657                 if (!augmentBuilder.isResolved()) {
658                     final SchemaPath augmentTargetSchemaPath = augmentBuilder
659                             .getTargetPath();
660                     final List<QName> path = augmentTargetSchemaPath.getPath();
661
662                     final QName qname = path.get(0);
663                     String prefix = qname.getPrefix();
664                     if (prefix == null) {
665                         prefix = module.getPrefix();
666                     }
667
668                     DataSchemaNodeBuilder currentParent = null;
669                     final ModuleBuilder dependentModule = findDependentModule(
670                             modules, module, prefix, augmentBuilder.getLine());
671                     for (DataSchemaNodeBuilder child : dependentModule
672                             .getChildNodes()) {
673                         final QName childQName = child.getQName();
674                         if (childQName.getLocalName().equals(
675                                 qname.getLocalName())) {
676                             currentParent = child;
677                             break;
678                         }
679                     }
680
681                     for (int i = 1; i < path.size(); i++) {
682                         final QName currentQName = path.get(i);
683                         DataSchemaNodeBuilder newParent = null;
684                         for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
685                                 .getChildNodes()) {
686                             final QName childQName = child.getQName();
687                             if (childQName.getLocalName().equals(
688                                     currentQName.getLocalName())) {
689                                 newParent = child;
690                                 break;
691                             }
692                         }
693                         if (newParent == null) {
694                             break; // node not found, quit search
695                         } else {
696                             currentParent = newParent;
697                         }
698                     }
699
700                     final QName currentQName = currentParent.getQName();
701                     final QName lastAugmentPathElement = path
702                             .get(path.size() - 1);
703                     if (currentQName.getLocalName().equals(
704                             lastAugmentPathElement.getLocalName())) {
705                         ParserUtils.fillAugmentTarget(augmentBuilder,
706                                 (ChildNodeBuilder) currentParent);
707                         ((AugmentationTargetBuilder) currentParent)
708                                 .addAugmentation(augmentBuilder);
709                         SchemaPath oldPath = currentParent.getPath();
710                         augmentBuilder.setTargetPath(new SchemaPath(oldPath
711                                 .getPath(), oldPath.isAbsolute()));
712                         augmentBuilder.setResolved(true);
713                         module.augmentResolved();
714                     }
715                 }
716
717             }
718         }
719     }
720
721     /**
722      * Go through identity statements defined in current module and resolve
723      * their 'base' statement if present.
724      *
725      * @param modules
726      *            all modules
727      * @param module
728      *            module being resolved
729      */
730     private void resolveIdentities(
731             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
732             final ModuleBuilder module) {
733         final Set<IdentitySchemaNodeBuilder> identities = module
734                 .getAddedIdentities();
735         for (IdentitySchemaNodeBuilder identity : identities) {
736             final String baseIdentityName = identity.getBaseIdentityName();
737             if (baseIdentityName != null) {
738                 String baseIdentityPrefix = null;
739                 String baseIdentityLocalName = null;
740                 if (baseIdentityName.contains(":")) {
741                     final String[] splitted = baseIdentityName.split(":");
742                     baseIdentityPrefix = splitted[0];
743                     baseIdentityLocalName = splitted[1];
744                 } else {
745                     baseIdentityPrefix = module.getPrefix();
746                     baseIdentityLocalName = baseIdentityName;
747                 }
748                 final ModuleBuilder dependentModule = findDependentModule(
749                         modules, module, baseIdentityPrefix, identity.getLine());
750
751                 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
752                         .getAddedIdentities();
753                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
754                     if (idBuilder.getQName().getLocalName()
755                             .equals(baseIdentityLocalName)) {
756                         identity.setBaseIdentity(idBuilder);
757                     }
758                 }
759             }
760         }
761     }
762
763     /**
764      * Go through uses statements defined in current module and resolve their
765      * refine statements.
766      *
767      * @param modules
768      *            all modules
769      * @param module
770      *            module being resolved
771      */
772     private void resolveUses(
773             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
774             final ModuleBuilder module) {
775         final Map<List<String>, UsesNodeBuilder> moduleUses = module
776                 .getAddedUsesNodes();
777         for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
778                 .entrySet()) {
779             final List<String> key = entry.getKey();
780             final UsesNodeBuilder usesNode = entry.getValue();
781             final int line = usesNode.getLine();
782
783             final String groupingName = key.get(key.size() - 1);
784
785             for (RefineHolder refine : usesNode.getRefines()) {
786                 Builder refineTarget = getRefineNodeBuilderCopy(groupingName,
787                         refine, modules, module);
788                 ParserUtils.refineDefault(refineTarget, refine, line);
789                 if (refineTarget instanceof LeafSchemaNodeBuilder) {
790                     final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
791                     ParserUtils.refineLeaf(leaf, refine, line);
792                     usesNode.addRefineNode(leaf);
793                 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
794                     final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
795                     ParserUtils.refineContainer(container, refine, line);
796                     usesNode.addRefineNode(container);
797                 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
798                     final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
799                     ParserUtils.refineList(list, refine, line);
800                     usesNode.addRefineNode(list);
801                 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
802                     final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) refineTarget;
803                     ParserUtils.refineLeafList(leafList, refine, line);
804                     usesNode.addRefineNode(leafList);
805                 } else if (refineTarget instanceof ChoiceBuilder) {
806                     final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
807                     ParserUtils.refineChoice(choice, refine, line);
808                     usesNode.addRefineNode(choice);
809                 } else if (refineTarget instanceof AnyXmlBuilder) {
810                     final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
811                     ParserUtils.refineAnyxml(anyXml, refine, line);
812                     usesNode.addRefineNode(anyXml);
813                 } else if(refineTarget instanceof GroupingBuilder) {
814                     usesNode.addRefineNode((GroupingBuilder)refineTarget);
815                 } else if(refineTarget instanceof TypedefBuilder) {
816                     usesNode.addRefineNode((TypedefBuilder)refineTarget);
817                 }
818             }
819         }
820     }
821
822     /**
823      * Find original builder of node to refine and return copy of this builder.
824      * <p>
825      * We must make a copy of builder to preserve original builder, because this
826      * object will be refined (modified) and later added to
827      * {@link UsesNodeBuilder}.
828      * </p>
829      *
830      * @param groupingPath
831      *            path to grouping which contains node to refine
832      * @param refine
833      *            refine object containing informations about refine
834      * @param modules
835      *            all loaded modules
836      * @param module
837      *            current module
838      * @return copy of node to be refined if it is present in grouping, null
839      *         otherwise
840      */
841     private Builder getRefineNodeBuilderCopy(final String groupingPath,
842             final RefineHolder refine,
843             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
844             final ModuleBuilder module) {
845         Builder result = null;
846         final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
847                 refine, modules, module);
848         if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
849             result = ParserUtils
850                     .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
851         } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
852             result = ParserUtils
853                     .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
854         } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
855             result = ParserUtils
856                     .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
857         } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
858             result = ParserUtils
859                     .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
860         } else if (lookedUpBuilder instanceof ChoiceBuilder) {
861             result = ParserUtils
862                     .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
863         } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
864             result = ParserUtils
865                     .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
866         } else if (lookedUpBuilder instanceof GroupingBuilder) {
867             result = ParserUtils
868                     .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder);
869         } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
870             result = ParserUtils
871                     .copyTypedefBuilder((TypedefBuilder) lookedUpBuilder);
872         } else {
873             throw new YangParseException(module.getName(), refine.getLine(),
874                     "Target '" + refine.getName() + "' can not be refined");
875         }
876         return result;
877     }
878
879     /**
880      * Find builder of refine node.
881      *
882      * @param groupingPath
883      *            path to grouping which contains node to refine
884      * @param refine
885      *            object containing refine information
886      * @param modules
887      *            all loaded modules
888      * @param module
889      *            current module
890      * @return Builder object of refine node if it is present in grouping, null
891      *         otherwise
892      */
893     private Builder findRefineTargetBuilder(final String groupingPath,
894             final RefineHolder refine,
895             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
896             final ModuleBuilder module) {
897         final String refineNodeName = refine.getName();
898         final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
899         final List<String> builderPath = new ArrayList<String>();
900         String prefix = null;
901         for (QName qname : path.getPath()) {
902             builderPath.add(qname.getLocalName());
903             prefix = qname.getPrefix();
904         }
905         if (prefix == null) {
906             prefix = module.getPrefix();
907         }
908
909         final ModuleBuilder dependentModule = findDependentModule(modules,
910                 module, prefix, refine.getLine());
911         builderPath.add(0, "grouping");
912         builderPath.add(0, dependentModule.getName());
913         final GroupingBuilder builder = (GroupingBuilder) dependentModule
914                 .getNode(builderPath);
915
916         Builder result = builder.getChildNode(refineNodeName);
917         if(result == null) {
918             Set<GroupingBuilder> grps = builder.getGroupings();
919             for(GroupingBuilder gr : grps) {
920                 if(gr.getQName().getLocalName().equals(refineNodeName)) {
921                     result = gr;
922                     break;
923                 }
924             }
925         }
926         if(result == null) {
927             Set<TypeDefinitionBuilder> typedefs = builder.getTypedefs();
928             for(TypeDefinitionBuilder typedef : typedefs) {
929                 if(typedef.getQName().getLocalName().equals(refineNodeName)) {
930                     result = typedef;
931                     break;
932                 }
933             }
934         }
935         return result;
936     }
937
938     private QName findFullQName(
939             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
940             final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
941         QName result = null;
942         String baseString = idref.getBaseString();
943         if (baseString.contains(":")) {
944             String[] splittedBase = baseString.split(":");
945             if (splittedBase.length > 2) {
946                 throw new YangParseException(module.getName(), idref.getLine(),
947                         "Failed to parse identityref base: " + baseString);
948             }
949             String prefix = splittedBase[0];
950             String name = splittedBase[1];
951             ModuleBuilder dependentModule = findDependentModule(modules,
952                     module, prefix, idref.getLine());
953             result = new QName(dependentModule.getNamespace(),
954                     dependentModule.getRevision(), prefix, name);
955         } else {
956             result = new QName(module.getNamespace(), module.getRevision(),
957                     module.getPrefix(), baseString);
958         }
959         return result;
960     }
961
962     private void resolveUnknownNodes(
963             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
964             final ModuleBuilder module) {
965         for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
966             QName nodeType = usnb.getNodeType();
967             if (nodeType.getNamespace() == null
968                     || nodeType.getRevision() == null) {
969                 try {
970                     ModuleBuilder dependentModule = findDependentModule(
971                             modules, module, nodeType.getPrefix(),
972                             usnb.getLine());
973                     QName newNodeType = new QName(
974                             dependentModule.getNamespace(),
975                             dependentModule.getRevision(),
976                             nodeType.getPrefix(), nodeType.getLocalName());
977                     usnb.setNodeType(newNodeType);
978                 } catch (YangParseException e) {
979                     logger.debug(module.getName(), usnb.getLine(),
980                             "Failed to find unknown node type: " + nodeType);
981                 }
982             }
983         }
984     }
985
986     /**
987      * Find dependent module based on given prefix
988      *
989      * @param modules
990      *            all available modules
991      * @param module
992      *            current module
993      * @param prefix
994      *            target module prefix
995      * @return
996      */
997     private ModuleBuilder findDependentModule(
998             final Map<String, TreeMap<Date, ModuleBuilder>> modules,
999             final ModuleBuilder module, final String prefix, final int line) {
1000         ModuleBuilder dependentModule = null;
1001         Date dependentModuleRevision = null;
1002
1003         if (prefix.equals(module.getPrefix())) {
1004             dependentModule = module;
1005         } else {
1006             final ModuleImport dependentModuleImport = ParserUtils
1007                     .getModuleImport(module, prefix);
1008             if (dependentModuleImport == null) {
1009                 throw new YangParseException(module.getName(), line,
1010                         "No import found with prefix '" + prefix + "'.");
1011             }
1012             final String dependentModuleName = dependentModuleImport
1013                     .getModuleName();
1014             dependentModuleRevision = dependentModuleImport.getRevision();
1015
1016             final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1017                     .get(dependentModuleName);
1018             if (moduleBuildersByRevision == null) {
1019                 throw new YangParseException(module.getName(), line,
1020                         "Failed to find dependent module '"
1021                                 + dependentModuleName + "'.");
1022             }
1023             if (dependentModuleRevision == null) {
1024                 dependentModule = moduleBuildersByRevision.lastEntry()
1025                         .getValue();
1026             } else {
1027                 dependentModule = moduleBuildersByRevision
1028                         .get(dependentModuleRevision);
1029             }
1030         }
1031
1032         if (dependentModule == null) {
1033             throw new YangParseException(module.getName(), line,
1034                     "Failed to find dependent module with prefix '" + prefix
1035                             + "' and revision '" + dependentModuleRevision
1036                             + "'.");
1037         }
1038         return dependentModule;
1039     }
1040
1041 }