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