54902232ea3df589f1c2faaa292b724f34299495
[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.util.ArrayList;
16 import java.util.Calendar;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Set;
23 import java.util.TreeMap;
24
25 import org.antlr.v4.runtime.ANTLRInputStream;
26 import org.antlr.v4.runtime.CommonTokenStream;
27 import org.antlr.v4.runtime.tree.ParseTree;
28 import org.antlr.v4.runtime.tree.ParseTreeWalker;
29 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
31 import org.opendaylight.controller.yang.common.QName;
32 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
33 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
34 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
35 import org.opendaylight.controller.yang.model.api.Module;
36 import org.opendaylight.controller.yang.model.api.ModuleImport;
37 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
38 import org.opendaylight.controller.yang.model.api.RpcDefinition;
39 import org.opendaylight.controller.yang.model.api.SchemaContext;
40 import org.opendaylight.controller.yang.model.api.SchemaPath;
41 import org.opendaylight.controller.yang.model.api.TypeDefinition;
42 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
46 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
47 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
48 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
49 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
50 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
51 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
52 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
53 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
54 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
55 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
56 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
60 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
61 import org.opendaylight.controller.yang.model.parser.util.YangParseException;
62 import org.opendaylight.controller.yang.model.util.ExtendedType;
63 import org.opendaylight.controller.yang.model.util.UnknownType;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 public class YangModelParserImpl implements YangModelParser {
68
69     private static final Logger logger = LoggerFactory
70             .getLogger(YangModelParserImpl.class);
71
72     @Override
73     public Module parseYangModel(final String yangFile) {
74         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);
75         final Set<Module> result = build(modules);
76         return result.iterator().next();
77     }
78
79     @Override
80     public Set<Module> parseYangModels(final String... yangFiles) {
81         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);
82         return build(modules);
83     }
84
85     @Override
86     public Set<Module> parseYangModelsFromStreams(
87             final InputStream... yangModelStreams) {
88         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);
89         return build(modules);
90     }
91
92     @Override
93     public SchemaContext resolveSchemaContext(final Set<Module> modules) {
94         return new SchemaContextImpl(modules);
95     }
96
97     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
98             String... yangFiles) {
99         InputStream[] streams = new InputStream[yangFiles.length];
100         FileInputStream inStream = null;
101         for (int i = 0; i < yangFiles.length; i++) {
102             final String yangFileName = yangFiles[i];
103             final File yangFile = new File(yangFileName);
104             try {
105                 inStream = new FileInputStream(yangFile);
106             } catch (FileNotFoundException e) {
107                 logger.warn("Exception while reading yang stream: " + inStream,
108                         e);
109             }
110             streams[i] = inStream;
111         }
112         return resolveModuleBuildersFromStreams(streams);
113     }
114
115     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
116             InputStream... yangFiles) {
117         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
118         final ParseTreeWalker walker = new ParseTreeWalker();
119         final List<ParseTree> trees = parseStreams(yangFiles);
120         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
121
122         // validation\r
123         // if validation fails with any file, do not continue and throw\r
124         // exception\r
125         for (int i = 0; i < trees.size(); i++) {\r
126             try {\r
127                 final YangModelValidationListener yangModelParser = new YangModelValidationListener();\r
128                 walker.walk(yangModelParser, trees.get(i));\r
129             } catch (IllegalStateException e) {\r
130                 // wrap exception to add information about which file failed\r
131                 throw new YangValidationException(\r
132                         "Yang validation failed for file" + yangFiles[i], e);\r
133             }\r
134         }\r
135
136
137         YangModelParserListenerImpl yangModelParser = null;
138         for (int i = 0; i < trees.size(); i++) {
139             yangModelParser = new YangModelParserListenerImpl();
140             walker.walk(yangModelParser, trees.get(i));
141             builders[i] = yangModelParser.getModuleBuilder();
142         }
143
144         for (ModuleBuilder builder : builders) {
145             final String builderName = builder.getName();
146             Date builderRevision = builder.getRevision();
147             if (builderRevision == null) {
148                 builderRevision = createEpochTime();
149             }
150             TreeMap<Date, ModuleBuilder> builderByRevision = modules
151                     .get(builderName);
152             if (builderByRevision == null) {
153                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
154             }
155             builderByRevision.put(builderRevision, builder);
156             modules.put(builderName, builderByRevision);
157         }
158         return modules;
159     }
160
161     private List<ParseTree> parseStreams(InputStream... yangStreams) {
162         final List<ParseTree> trees = new ArrayList<ParseTree>();
163         for (InputStream yangStream : yangStreams) {
164             trees.add(parseStream(yangStream));
165         }
166         return trees;
167     }
168
169     private ParseTree parseStream(InputStream yangStream) {
170         ParseTree result = null;
171         try {
172             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
173             final YangLexer lexer = new YangLexer(input);
174             final CommonTokenStream tokens = new CommonTokenStream(lexer);
175             final YangParser parser = new YangParser(tokens);
176             result = parser.yang();
177         } catch (IOException e) {
178             logger.warn("Exception while reading yang file: " + yangStream, e);
179         }
180         return result;
181     }
182
183     private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
184         // validate
185         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
186                 .entrySet()) {
187             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
188                     .entrySet()) {
189                 ModuleBuilder moduleBuilder = childEntry.getValue();
190                 validateModule(modules, moduleBuilder);
191             }
192         }
193
194         // build
195         final Set<Module> result = new HashSet<Module>();
196         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
197                 .entrySet()) {
198             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
199             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
200                     .entrySet()) {
201                 ModuleBuilder moduleBuilder = childEntry.getValue();
202                 Module module = moduleBuilder.build();
203                 modulesByRevision.put(childEntry.getKey(), module);
204                 result.add(module);
205             }
206         }
207         return result;
208     }
209
210     private void validateModule(
211             Map<String, TreeMap<Date, ModuleBuilder>> modules,
212             ModuleBuilder builder) {
213         resolveDirtyNodes(modules, builder);
214         resolveAugments(modules, builder);
215         resolveIdentities(modules, builder);
216     }
217
218     /**
219      * Search for dirty nodes (node which contains UnknownType) and resolve
220      * unknown types.
221      *
222      * @param modules
223      *            all available modules
224      * @param module
225      *            current module
226      */
227     private void resolveDirtyNodes(
228             Map<String, TreeMap<Date, ModuleBuilder>> modules,
229             ModuleBuilder module) {
230         final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
231                 .getDirtyNodes();
232         if (!dirtyNodes.isEmpty()) {
233             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
234                     .entrySet()) {
235
236                 TypeAwareBuilder typeToResolve = entry.getValue();
237                 if (typeToResolve instanceof UnionTypeBuilder) {
238                     UnionTypeBuilder union = (UnionTypeBuilder) typeToResolve;
239                     List<TypeDefinition<?>> unionTypes = union.getTypes();
240                     List<UnknownType> toRemove = new ArrayList<UnknownType>();
241                     for (TypeDefinition<?> td : unionTypes) {
242                         if (td instanceof UnknownType) {
243                             UnknownType unknownType = (UnknownType) td;
244                             TypeDefinitionBuilder resolvedType = findTargetTypeUnion(
245                                     typeToResolve, unknownType, modules, module);
246                             union.setType(resolvedType);
247                             toRemove.add(unknownType);
248                         }
249                     }
250                     unionTypes.removeAll(toRemove);
251                 } else {
252                     TypeDefinitionBuilder resolvedType = findTargetType(
253                             typeToResolve, modules, module);
254                     typeToResolve.setType(resolvedType);
255                 }
256             }
257         }
258     }
259
260     private TypeDefinitionBuilder findTargetType(
261             TypeAwareBuilder typeToResolve,
262             Map<String, TreeMap<Date, ModuleBuilder>> modules,
263             ModuleBuilder builder) {
264         TypeConstraints constraints = new TypeConstraints();
265
266         TypeDefinitionBuilder targetType = findTypedef(typeToResolve, modules,
267                 builder);
268         TypeConstraints tConstraints = findConstraints(typeToResolve,
269                 constraints, modules, builder);
270         targetType.setRanges(tConstraints.getRange());
271         targetType.setLengths(tConstraints.getLength());
272         targetType.setPatterns(tConstraints.getPatterns());
273         targetType.setFractionDigits(tConstraints.getFractionDigits());
274
275         return targetType;
276     }
277
278     private TypeDefinitionBuilder findTargetTypeUnion(
279             TypeAwareBuilder typeToResolve, UnknownType unknownType,
280             Map<String, TreeMap<Date, ModuleBuilder>> modules,
281             ModuleBuilder builder) {
282         TypeConstraints constraints = new TypeConstraints();
283
284         TypeDefinitionBuilder targetType = findTypedefUnion(typeToResolve,
285                 unknownType, modules, builder);
286         TypeConstraints tConstraints = findConstraints(typeToResolve,
287                 constraints, modules, builder);
288         targetType.setRanges(tConstraints.getRange());
289         targetType.setLengths(tConstraints.getLength());
290         targetType.setPatterns(tConstraints.getPatterns());
291         targetType.setFractionDigits(tConstraints.getFractionDigits());
292
293         return targetType;
294     }
295
296     private TypeDefinitionBuilder findTypedef(TypeAwareBuilder typeToResolve,
297             Map<String, TreeMap<Date, ModuleBuilder>> modules,
298             ModuleBuilder builder) {
299
300         TypeDefinition<?> baseTypeToResolve = typeToResolve.getType();
301         if (baseTypeToResolve != null
302                 && !(baseTypeToResolve instanceof UnknownType)) {
303             return (TypeDefinitionBuilder) typeToResolve;
304         }
305
306         UnknownType unknownType = (UnknownType) typeToResolve.getType();
307
308         QName unknownTypeQName = unknownType.getQName();
309         String unknownTypeName = unknownTypeQName.getLocalName();
310         String unknownTypePrefix = unknownTypeQName.getPrefix();
311
312         // search for module which contains referenced typedef
313         ModuleBuilder dependentModule = findDependentModule(modules, builder,
314                 unknownTypePrefix);
315         TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
316                 dependentModule.getModuleTypedefs(), unknownTypeName);
317
318         TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
319                 lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder);
320         TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
321                 lookedUpBuilderCopy, modules, dependentModule);
322         return resolvedCopy;
323     }
324
325     private TypeDefinitionBuilder findTypedefUnion(
326             TypeAwareBuilder typeToResolve, UnknownType unknownType,
327             Map<String, TreeMap<Date, ModuleBuilder>> modules,
328             ModuleBuilder builder) {
329
330         TypeDefinition<?> baseTypeToResolve = typeToResolve.getType();
331         if (baseTypeToResolve != null
332                 && !(baseTypeToResolve instanceof UnknownType)) {
333             return (TypeDefinitionBuilder) typeToResolve;
334         }
335
336         QName unknownTypeQName = unknownType.getQName();
337         String unknownTypeName = unknownTypeQName.getLocalName();
338         String unknownTypePrefix = unknownTypeQName.getPrefix();
339
340         // search for module which contains referenced typedef
341         ModuleBuilder dependentModule = findDependentModule(modules, builder,
342                 unknownTypePrefix);
343         TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
344                 dependentModule.getModuleTypedefs(), unknownTypeName);
345
346         TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
347                 lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder);
348         TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
349                 lookedUpBuilderCopy, modules, dependentModule);
350         return resolvedCopy;
351     }
352
353     private TypeDefinitionBuilder copyTypedefBuilder(TypeDefinitionBuilder old,
354             boolean seekByTypedefBuilder) {
355         if (old instanceof UnionTypeBuilder) {
356             UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
357             UnionTypeBuilder newUnion = new UnionTypeBuilder();
358             for (TypeDefinition<?> td : oldUnion.getTypes()) {
359                 newUnion.setType(td);
360             }
361             for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
362                 newUnion.setType(copyTypedefBuilder(tdb, true));
363             }
364             return newUnion;
365         }
366
367         QName oldQName = old.getQName();
368         QName newQName = new QName(oldQName.getNamespace(),
369                 oldQName.getRevision(), oldQName.getPrefix(),
370                 oldQName.getLocalName());
371         TypeDefinitionBuilder tdb = new TypedefBuilder(newQName);
372
373         tdb.setRanges(old.getRanges());
374         tdb.setLengths(old.getLengths());
375         tdb.setPatterns(old.getPatterns());
376
377         TypeDefinition<?> oldType = old.getType();
378         if (oldType == null) {
379             tdb.setType(old.getTypedef());
380         } else {
381             tdb.setType(oldType);
382         }
383
384         if (!seekByTypedefBuilder) {
385             tdb.setDescription(old.getDescription());
386             tdb.setReference(old.getReference());
387             tdb.setStatus(old.getStatus());
388             tdb.setDefaultValue(old.getDefaultValue());
389             tdb.setUnits(old.getUnits());
390         }
391         return tdb;
392     }
393
394     private TypeDefinitionBuilder resolveCopiedBuilder(
395             TypeDefinitionBuilder copied,
396             Map<String, TreeMap<Date, ModuleBuilder>> modules,
397             ModuleBuilder builder) {
398
399         if (copied instanceof UnionTypeBuilder) {
400             UnionTypeBuilder union = (UnionTypeBuilder) copied;
401             List<TypeDefinition<?>> unionTypes = union.getTypes();
402             List<UnknownType> toRemove = new ArrayList<UnknownType>();
403             for (TypeDefinition<?> td : unionTypes) {
404                 if (td instanceof UnknownType) {
405                     UnknownType unknownType = (UnknownType) td;
406                     TypeDefinitionBuilder resolvedType = findTargetTypeUnion(
407                             union, unknownType, modules, builder);
408                     union.setType(resolvedType);
409                     toRemove.add(unknownType);
410                 }
411             }
412             unionTypes.removeAll(toRemove);
413
414             return union;
415         }
416
417         TypeDefinition<?> base = copied.getType();
418         TypeDefinitionBuilder baseTdb = copied.getTypedef();
419         if (base != null && !(base instanceof UnknownType)) {
420             return copied;
421         } else if (base instanceof UnknownType) {
422             UnknownType unknownType = (UnknownType) base;
423             QName unknownTypeQName = unknownType.getQName();
424             String unknownTypePrefix = unknownTypeQName.getPrefix();
425             ModuleBuilder dependentModule = findDependentModule(modules,
426                     builder, unknownTypePrefix);
427             TypeDefinitionBuilder unknownTypeBuilder = findTypedef(copied,
428                     modules, dependentModule);
429             copied.setType(unknownTypeBuilder);
430             return copied;
431         } else if (base == null && baseTdb != null) {
432             // make a copy of baseTypeDef and call again
433             TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(baseTdb,
434                     true);
435             TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
436                     baseTdbCopy, modules, builder);
437             copied.setType(baseTdbCopyResolved);
438             return copied;
439         } else {
440             throw new IllegalStateException(
441                     "TypeDefinitionBuilder in unexpected state");
442         }
443     }
444
445     private TypeDefinitionBuilder findTypedef(QName unknownTypeQName,
446             Map<String, TreeMap<Date, ModuleBuilder>> modules,
447             ModuleBuilder builder) {
448
449         String unknownTypeName = unknownTypeQName.getLocalName();
450         String unknownTypePrefix = unknownTypeQName.getPrefix();
451
452         // search for module which contains referenced typedef
453         ModuleBuilder dependentModule = findDependentModule(modules, builder,
454                 unknownTypePrefix);
455
456         TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
457                 dependentModule.getModuleTypedefs(), unknownTypeName);
458
459         TypeDefinitionBuilder copied = copyTypedefBuilder(lookedUpBuilder, true);
460         return copied;
461     }
462
463     private TypeConstraints findConstraints(TypeAwareBuilder typeToResolve,
464             TypeConstraints constraints,
465             Map<String, TreeMap<Date, ModuleBuilder>> modules,
466             ModuleBuilder builder) {
467
468         // union type cannot be restricted
469         if (typeToResolve instanceof UnionTypeBuilder) {
470             return constraints;
471         }
472
473         // if referenced type is UnknownType again, search recursively with
474         // current constraints
475         TypeDefinition<?> referencedType = typeToResolve.getType();
476         if (referencedType == null) {
477             TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) typeToResolve;
478             final List<RangeConstraint> ranges = tdb.getRanges();
479             constraints.addRanges(ranges);
480             final List<LengthConstraint> lengths = tdb.getLengths();
481             constraints.addLengths(lengths);
482             final List<PatternConstraint> patterns = tdb.getPatterns();
483             constraints.addPatterns(patterns);
484             final Integer fractionDigits = tdb.getFractionDigits();
485             constraints.setFractionDigits(fractionDigits);
486             return constraints;
487         } else if (referencedType instanceof ExtendedType) {
488             ExtendedType ext = (ExtendedType) referencedType;
489             final List<RangeConstraint> ranges = ext.getRanges();
490             constraints.addRanges(ranges);
491             final List<LengthConstraint> lengths = ext.getLengths();
492             constraints.addLengths(lengths);
493             final List<PatternConstraint> patterns = ext.getPatterns();
494             constraints.addPatterns(patterns);
495             final Integer fractionDigits = ext.getFractionDigits();
496             constraints.setFractionDigits(fractionDigits);
497             return findConstraints(
498                     findTypedef(ext.getQName(), modules, builder), constraints,
499                     modules, builder);
500         } else if (referencedType instanceof UnknownType) {
501             UnknownType unknown = (UnknownType) referencedType;
502
503             final List<RangeConstraint> ranges = unknown.getRangeStatements();
504             constraints.addRanges(ranges);
505             final List<LengthConstraint> lengths = unknown
506                     .getLengthStatements();
507             constraints.addLengths(lengths);
508             final List<PatternConstraint> patterns = unknown.getPatterns();
509             constraints.addPatterns(patterns);
510             final Integer fractionDigits = unknown.getFractionDigits();
511             constraints.setFractionDigits(fractionDigits);
512
513             String unknownTypePrefix = unknown.getQName().getPrefix();
514             if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
515                 unknownTypePrefix = builder.getPrefix();
516             }
517             ModuleBuilder dependentModule = findDependentModule(modules,
518                     builder, unknown.getQName().getPrefix());
519             TypeDefinitionBuilder unknownTypeBuilder = findTypedef(
520                     unknown.getQName(), modules, builder);
521             return findConstraints(unknownTypeBuilder, constraints, modules,
522                     dependentModule);
523         } else {
524             // HANDLE BASE YANG TYPE
525             mergeConstraints(referencedType, constraints);
526             return constraints;
527         }
528
529     }
530
531     /**
532      * Go through all typedef statements from given module and search for one
533      * with given name
534      *
535      * @param typedefs
536      *            typedef statements to search
537      * @param name
538      *            name of searched typedef
539      * @return typedef with name equals to given name
540      */
541     private TypeDefinitionBuilder findTypedefBuilder(
542             Set<TypeDefinitionBuilder> typedefs, String name) {
543         TypeDefinitionBuilder result = null;
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(
552                     "Target module does not contain typedef '" + name + "'.");
553         }
554         return result;
555     }
556
557     /**
558      * Pull restriction from referenced type and add them to given constraints
559      *
560      * @param referencedType
561      * @param constraints
562      */
563     private void mergeConstraints(TypeDefinition<?> referencedType,
564             TypeConstraints constraints) {
565
566         if (referencedType instanceof DecimalTypeDefinition) {
567             constraints.addRanges(((DecimalTypeDefinition) referencedType)
568                     .getRangeStatements());
569             constraints
570                     .setFractionDigits(((DecimalTypeDefinition) referencedType)
571                             .getFractionDigits());
572         } else if (referencedType instanceof IntegerTypeDefinition) {
573             constraints.addRanges(((IntegerTypeDefinition) referencedType)
574                     .getRangeStatements());
575         } else if (referencedType instanceof StringTypeDefinition) {
576             constraints.addPatterns(((StringTypeDefinition) referencedType)
577                     .getPatterns());
578             constraints.addLengths(((StringTypeDefinition) referencedType)
579                     .getLengthStatements());
580         } else if (referencedType instanceof BinaryTypeDefinition) {
581             constraints.addLengths(((BinaryTypeDefinition) referencedType)
582                     .getLengthConstraints());
583         }
584     }
585
586     /**
587      * Go through all augmentation definitions and resolve them. This means find
588      * referenced node and add child nodes to it.
589      *
590      * @param modules
591      *            all available modules
592      * @param module
593      *            current module
594      */
595     private void resolveAugments(
596             Map<String, TreeMap<Date, ModuleBuilder>> modules,
597             ModuleBuilder module) {
598         Set<AugmentationSchemaBuilder> augmentBuilders = module
599                 .getAddedAugments();
600
601         Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
602         for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
603             SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
604             String prefix = null;
605             List<String> augmentTargetPath = new ArrayList<String>();
606
607             for (QName pathPart : augmentTargetSchemaPath.getPath()) {
608                 prefix = pathPart.getPrefix();
609                 augmentTargetPath.add(pathPart.getLocalName());
610             }
611             ModuleBuilder dependentModule = findDependentModule(modules,
612                     module, prefix);
613             augmentTargetPath.add(0, dependentModule.getName());
614
615             AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
616                     .getNode(augmentTargetPath);
617             AugmentationSchema result = augmentBuilder.build();
618             augmentTarget.addAugmentation(result);
619             fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
620             augments.add(result);
621         }
622         module.setAugmentations(augments);
623     }
624
625     /**
626      * Add all augment's child nodes to given target.
627      *
628      * @param augment
629      * @param target
630      */
631     private void fillAugmentTarget(AugmentationSchemaBuilder augment,
632             ChildNodeBuilder target) {
633         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
634             builder.setAugmenting(true);
635             target.addChildNode(builder);
636         }
637     }
638
639     /**
640      * Go through identity statements defined in current module and resolve
641      * their 'base' statement if present.
642      *
643      * @param modules
644      *            all modules
645      * @param module
646      *            module being resolved
647      */
648     private void resolveIdentities(
649             Map<String, TreeMap<Date, ModuleBuilder>> modules,
650             ModuleBuilder module) {
651         Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
652         for (IdentitySchemaNodeBuilder identity : identities) {
653             String baseIdentityName = identity.getBaseIdentityName();
654             if (baseIdentityName != null) {
655                 String baseIdentityPrefix = null;
656                 String baseIdentityLocalName = null;
657                 if (baseIdentityName.contains(":")) {
658                     String[] splitted = baseIdentityName.split(":");
659                     baseIdentityPrefix = splitted[0];
660                     baseIdentityLocalName = splitted[1];
661                 } else {
662                     baseIdentityPrefix = module.getPrefix();
663                     baseIdentityLocalName = baseIdentityName;
664                 }
665                 ModuleBuilder dependentModule = findDependentModule(modules,
666                         module, baseIdentityPrefix);
667
668                 Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
669                         .getAddedIdentities();
670                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
671                     if (idBuilder.getQName().getLocalName()
672                             .equals(baseIdentityLocalName)) {
673                         identity.setBaseIdentity(idBuilder);
674                     }
675                 }
676             }
677         }
678     }
679
680     /**
681      * Find dependent module based on given prefix
682      *
683      * @param modules
684      *            all available modules
685      * @param module
686      *            current module
687      * @param prefix
688      *            target module prefix
689      * @return
690      */
691     private ModuleBuilder findDependentModule(
692             Map<String, TreeMap<Date, ModuleBuilder>> modules,
693             ModuleBuilder module, String prefix) {
694         ModuleBuilder dependentModule = null;
695         Date dependentModuleRevision = null;
696
697         if (prefix.equals(module.getPrefix())) {
698             dependentModule = module;
699         } else {
700             ModuleImport dependentModuleImport = getModuleImport(module, prefix);
701             if (dependentModuleImport == null) {
702                 throw new YangParseException("No import found with prefix '"
703                         + prefix + "' in module " + module.getName() + "'.");
704             }
705             String dependentModuleName = dependentModuleImport.getModuleName();
706             dependentModuleRevision = dependentModuleImport.getRevision();
707
708             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
709                     .get(dependentModuleName);
710             if (dependentModuleRevision == null) {
711                 dependentModule = moduleBuildersByRevision.lastEntry()
712                         .getValue();
713             } else {
714                 dependentModule = moduleBuildersByRevision
715                         .get(dependentModuleRevision);
716             }
717         }
718
719         if (dependentModule == null) {
720             throw new YangParseException(
721                     "Failed to find dependent module with prefix '" + prefix
722                             + "' and revision '" + dependentModuleRevision
723                             + "'.");
724         }
725         return dependentModule;
726     }
727
728     /**
729      * Get module import referenced by given prefix.
730      *
731      * @param builder
732      *            module to search
733      * @param prefix
734      *            prefix associated with import
735      * @return ModuleImport based on given prefix
736      */
737     private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
738         ModuleImport moduleImport = null;
739         for (ModuleImport mi : builder.getModuleImports()) {
740             if (mi.getPrefix().equals(prefix)) {
741                 moduleImport = mi;
742                 break;
743             }
744         }
745         return moduleImport;
746     }
747
748     private Date createEpochTime() {
749         Calendar calendar = Calendar.getInstance();
750         calendar.setTimeInMillis(0);
751         return calendar.getTime();
752     }
753
754     private static class SchemaContextImpl implements SchemaContext {
755         private final Set<Module> modules;
756
757         private SchemaContextImpl(Set<Module> modules) {
758             this.modules = modules;
759         }
760
761         @Override
762         public Set<DataSchemaNode> getDataDefinitions() {
763             final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
764             for (Module m : modules) {
765                 dataDefs.addAll(m.getChildNodes());
766             }
767             return dataDefs;
768         }
769
770         @Override
771         public Set<Module> getModules() {
772             return modules;
773         }
774
775         @Override
776         public Set<NotificationDefinition> getNotifications() {
777             final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
778             for (Module m : modules) {
779                 notifications.addAll(m.getNotifications());
780             }
781             return notifications;
782         }
783
784         @Override
785         public Set<RpcDefinition> getOperations() {
786             final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
787             for (Module m : modules) {
788                 rpcs.addAll(m.getRpcs());
789             }
790             return rpcs;
791         }
792
793         @Override
794         public Set<ExtensionDefinition> getExtensions() {
795             final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
796             for (Module m : modules) {
797                 extensions.addAll(m.getExtensionSchemaNodes());
798             }
799             return extensions;
800         }
801     }
802
803 }