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