YANG model parser refactoring
[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.Collections;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TreeMap;
25
26 import org.antlr.v4.runtime.ANTLRInputStream;
27 import org.antlr.v4.runtime.CommonTokenStream;
28 import org.antlr.v4.runtime.tree.ParseTree;
29 import org.antlr.v4.runtime.tree.ParseTreeWalker;
30 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
32 import org.opendaylight.controller.yang.common.QName;
33 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
34 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
35 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
36 import org.opendaylight.controller.yang.model.api.Module;
37 import org.opendaylight.controller.yang.model.api.ModuleImport;
38 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
39 import org.opendaylight.controller.yang.model.api.RpcDefinition;
40 import org.opendaylight.controller.yang.model.api.SchemaContext;
41 import org.opendaylight.controller.yang.model.api.SchemaPath;
42 import org.opendaylight.controller.yang.model.api.TypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
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.ChildNodeBuilder;
56 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
62 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
63 import org.opendaylight.controller.yang.model.parser.util.YangParseException;
64 import org.opendaylight.controller.yang.model.util.BinaryType;
65 import org.opendaylight.controller.yang.model.util.BitsType;
66 import org.opendaylight.controller.yang.model.util.StringType;
67 import org.opendaylight.controller.yang.model.util.UnknownType;
68 import org.opendaylight.controller.yang.model.util.YangTypesConverter;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71
72 public class YangModelParserImpl implements YangModelParser {
73
74     private static final Logger logger = LoggerFactory
75             .getLogger(YangModelParserImpl.class);
76
77     @Override
78     public Module parseYangModel(String yangFile) {
79         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFile);
80         Set<Module> result = build(modules);
81         return result.iterator().next();
82     }
83
84     @Override
85     public Set<Module> parseYangModels(String... yangFiles) {
86         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangFiles);
87         Set<Module> result = build(modules);
88         return result;
89     }
90
91     @Override
92     public Set<Module> parseYangModelsFromStreams(
93             InputStream... yangModelStreams) {
94         final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersFromStreams(yangModelStreams);
95         Set<Module> result = build(modules);
96         return result;
97     }
98
99     @Override
100     public SchemaContext resolveSchemaContext(Set<Module> modules) {
101         return new SchemaContextImpl(modules);
102     }
103
104     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
105             String... yangFiles) {
106         InputStream[] streams = new InputStream[yangFiles.length];
107         for (int i = 0; i < yangFiles.length; i++) {
108             final String yangFileName = yangFiles[i];
109             final File yangFile = new File(yangFileName);
110             FileInputStream inStream = null;
111             try {
112                 inStream = new FileInputStream(yangFile);
113             } catch (FileNotFoundException e) {
114                 logger.warn("Exception while reading yang stream: " + inStream,
115                         e);
116             }
117             streams[i] = inStream;
118         }
119         return resolveModuleBuildersFromStreams(streams);
120     }
121
122     private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersFromStreams(
123             InputStream... yangFiles) {
124         final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
125         final ParseTreeWalker walker = new ParseTreeWalker();
126         final List<ParseTree> trees = parseStreams(yangFiles);
127         final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
128
129         for (int i = 0; i < trees.size(); i++) {
130             final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl();
131             walker.walk(yangModelParser, trees.get(i));
132             builders[i] = yangModelParser.getModuleBuilder();
133         }
134
135         for (ModuleBuilder builder : builders) {
136             final String builderName = builder.getName();
137             Date builderRevision = builder.getRevision();
138             if (builderRevision == null) {
139                 builderRevision = createEpochTime();
140             }
141             TreeMap<Date, ModuleBuilder> builderByRevision = modules
142                     .get(builderName);
143             if (builderByRevision == null) {
144                 builderByRevision = new TreeMap<Date, ModuleBuilder>();
145             }
146             builderByRevision.put(builderRevision, builder);
147             modules.put(builderName, builderByRevision);
148         }
149         return modules;
150     }
151
152     private List<ParseTree> parseStreams(InputStream... yangStreams) {
153         List<ParseTree> trees = new ArrayList<ParseTree>();
154         for (InputStream yangStream : yangStreams) {
155             trees.add(parseStream(yangStream));
156         }
157         return trees;
158     }
159
160     private ParseTree parseStream(InputStream yangStream) {
161         ParseTree result = null;
162         try {
163             final ANTLRInputStream input = new ANTLRInputStream(yangStream);
164             final YangLexer lexer = new YangLexer(input);
165             final CommonTokenStream tokens = new CommonTokenStream(lexer);
166             final YangParser parser = new YangParser(tokens);
167             result = parser.yang();
168         } catch (IOException e) {
169             logger.warn("Exception while reading yang file: " + yangStream, e);
170         }
171         return result;
172     }
173
174     private Set<Module> build(Map<String, TreeMap<Date, ModuleBuilder>> modules) {
175         // validate
176         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
177                 .entrySet()) {
178             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
179                     .entrySet()) {
180                 ModuleBuilder moduleBuilder = childEntry.getValue();
181                 validateBuilder(modules, moduleBuilder);
182             }
183         }
184         // build
185         final Set<Module> result = new HashSet<Module>();
186         for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
187                 .entrySet()) {
188             final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
189             for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
190                     .entrySet()) {
191                 ModuleBuilder moduleBuilder = childEntry.getValue();
192                 modulesByRevision.put(childEntry.getKey(),
193                         moduleBuilder.build());
194                 result.add(moduleBuilder.build());
195             }
196         }
197
198         return result;
199     }
200
201     private void validateBuilder(
202             Map<String, TreeMap<Date, ModuleBuilder>> modules,
203             ModuleBuilder builder) {
204         resolveTypedefs(modules, builder);
205         resolveAugments(modules, builder);
206         resolveIdentities(modules, builder);
207     }
208
209     /**
210      * Search for dirty nodes (node which contains UnknownType) and resolve
211      * unknown types.
212      *
213      * @param modules
214      *            all available modules
215      * @param module
216      *            current module
217      */
218     private void resolveTypedefs(
219             Map<String, TreeMap<Date, ModuleBuilder>> modules,
220             ModuleBuilder module) {
221         Map<List<String>, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
222         if (dirtyNodes.size() == 0) {
223             return;
224         } else {
225             for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
226                     .entrySet()) {
227                 TypeAwareBuilder typeToResolve = entry.getValue();
228
229                 if (typeToResolve instanceof UnionTypeBuilder) {
230                     resolveUnionTypeBuilder(modules, module,
231                             (UnionTypeBuilder) typeToResolve);
232                 } else {
233                     UnknownType ut = (UnknownType) typeToResolve.getType();
234                     TypeDefinition<?> resolvedType = findTargetType(ut,
235                             modules, module);
236                     typeToResolve.setType(resolvedType);
237                 }
238             }
239         }
240     }
241
242     private UnionTypeBuilder resolveUnionTypeBuilder(
243             Map<String, TreeMap<Date, ModuleBuilder>> modules,
244             ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) {
245         List<TypeDefinition<?>> resolvedTypes = new ArrayList<TypeDefinition<?>>();
246         List<TypeDefinition<?>> typesToRemove = new ArrayList<TypeDefinition<?>>();
247
248         for (TypeDefinition<?> td : unionTypeBuilderToResolve.getTypes()) {
249             if (td instanceof UnknownType) {
250                 TypeDefinition<?> resolvedType = findTargetType(
251                         (UnknownType) td, modules, builder);
252                 resolvedTypes.add(resolvedType);
253                 typesToRemove.add(td);
254             }
255         }
256
257         List<TypeDefinition<?>> unionTypeBuilderTypes = unionTypeBuilderToResolve
258                 .getTypes();
259         unionTypeBuilderTypes.addAll(resolvedTypes);
260         unionTypeBuilderTypes.removeAll(typesToRemove);
261
262         return unionTypeBuilderToResolve;
263     }
264
265     private TypeDefinition<?> findTargetType(UnknownType ut,
266             Map<String, TreeMap<Date, ModuleBuilder>> modules,
267             ModuleBuilder builder) {
268
269         TypeConstraints constraints = new TypeConstraints();
270         // RANGE
271         List<RangeConstraint> ranges = ut.getRangeStatements();
272         constraints.addRanges(ranges);
273         // LENGTH
274         List<LengthConstraint> lengths = ut.getLengthStatements();
275         constraints.addLengths(lengths);
276         // PATTERN
277         List<PatternConstraint> patterns = ut.getPatterns();
278         constraints.addPatterns(patterns);
279         // Fraction Digits
280         Integer fractionDigits = ut.getFractionDigits();
281
282         Map<TypeDefinitionBuilder, TypeConstraints> foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints(
283                 constraints, modules, ut, builder);
284         TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder
285                 .entrySet().iterator().next().getKey();
286
287         TypeDefinition<?> targetTypeBaseType = targetType.getBaseType();
288         targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints,
289                 fractionDigits);
290
291         return targetTypeBaseType;
292     }
293
294     /**
295      * Traverse through all referenced types chain until base YANG type is
296      * founded.
297      *
298      * @param constraints
299      *            current type constraints
300      * @param modules
301      *            all available modules
302      * @param unknownType
303      *            unknown type
304      * @param builder
305      *            current module
306      * @return map, where key is type referenced and value is its constraints
307      */
308     private Map<TypeDefinitionBuilder, TypeConstraints> findTypeDefinitionBuilderWithConstraints(
309             TypeConstraints constraints,
310             Map<String, TreeMap<Date, ModuleBuilder>> modules,
311             UnknownType unknownType, ModuleBuilder builder) {
312         Map<TypeDefinitionBuilder, TypeConstraints> result = new HashMap<TypeDefinitionBuilder, TypeConstraints>();
313         QName unknownTypeQName = unknownType.getQName();
314         String unknownTypeName = unknownTypeQName.getLocalName();
315         String unknownTypePrefix = unknownTypeQName.getPrefix();
316
317         // search for module which contains referenced typedef
318         ModuleBuilder dependentModuleBuilder = findDependentModule(modules,
319                 builder, unknownTypePrefix);
320
321         TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder(
322                 dependentModuleBuilder.getModuleTypedefs(), unknownTypeName);
323
324         // if referenced type is UnknownType again, search recursively with
325         // current constraints
326         TypeDefinition<?> referencedType = lookedUpBuilder.getBaseType();
327         if (referencedType instanceof UnknownType) {
328             UnknownType unknown = (UnknownType) referencedType;
329
330             final List<RangeConstraint> ranges = unknown.getRangeStatements();
331             constraints.addRanges(ranges);
332             final List<LengthConstraint> lengths = unknown
333                     .getLengthStatements();
334             constraints.addLengths(lengths);
335             final List<PatternConstraint> patterns = unknown.getPatterns();
336             constraints.addPatterns(patterns);
337             return findTypeDefinitionBuilderWithConstraints(constraints,
338                     modules, unknown, dependentModuleBuilder);
339         } else {
340             mergeConstraints(referencedType, constraints);
341             result.put(lookedUpBuilder, constraints);
342             return result;
343         }
344     }
345
346     /**
347      * Go through all typedef statements from given module and search for one
348      * with given name
349      *
350      * @param typedefs
351      *            typedef statements to search
352      * @param name
353      *            name of searched typedef
354      * @return typedef with name equals to given name
355      */
356     private TypeDefinitionBuilder findTypedefBuilder(
357             Set<TypeDefinitionBuilder> typedefs, String name) {
358         TypeDefinitionBuilder result = null;
359         for (TypeDefinitionBuilder td : typedefs) {
360             if (td.getQName().getLocalName().equals(name)) {
361                 result = td;
362                 break;
363             }
364         }
365         if (result == null) {
366             throw new YangParseException(
367                     "Target module does not contain typedef '" + name + "'.");
368         }
369         return result;
370     }
371
372     /**
373      * Merge curent constraints with founded type constraints
374      *
375      * @param targetTypeBaseType
376      * @param constraints
377      * @param fractionDigits
378      * @return
379      */
380     private TypeDefinition<?> mergeConstraints(
381             TypeDefinition<?> targetTypeBaseType, TypeConstraints constraints,
382             Integer fractionDigits) {
383         String targetTypeBaseTypeName = targetTypeBaseType.getQName()
384                 .getLocalName();
385         // enumeration, leafref and identityref omitted because they have no
386         // restrictions
387         if (targetTypeBaseType instanceof DecimalTypeDefinition) {
388             List<RangeConstraint> ranges = constraints.getRange();
389             Integer fd = fractionDigits == null ? constraints
390                     .getFractionDigits() : fractionDigits;
391             targetTypeBaseType = YangTypesConverter
392                     .javaTypeForBaseYangDecimal64Type(ranges, fd);
393         } else if (targetTypeBaseType instanceof IntegerTypeDefinition) {
394             List<RangeConstraint> ranges = constraints.getRange();
395             if (targetTypeBaseTypeName.startsWith("int")) {
396                 targetTypeBaseType = YangTypesConverter
397                         .javaTypeForBaseYangSignedIntegerType(
398                                 targetTypeBaseTypeName, ranges);
399             } else {
400                 targetTypeBaseType = YangTypesConverter
401                         .javaTypeForBaseYangUnsignedIntegerType(
402                                 targetTypeBaseTypeName, ranges);
403             }
404         } else if (targetTypeBaseType instanceof StringTypeDefinition) {
405             List<LengthConstraint> lengths = constraints.getLength();
406             List<PatternConstraint> patterns = constraints.getPatterns();
407             targetTypeBaseType = new StringType(lengths, patterns);
408         } else if (targetTypeBaseType instanceof BitsTypeDefinition) {
409             BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType;
410             List<Bit> bits = bitsType.getBits();
411             targetTypeBaseType = new BitsType(bits);
412         } else if (targetTypeBaseType instanceof BinaryTypeDefinition) {
413             List<LengthConstraint> lengths = constraints.getLength();
414             List<Byte> bytes = Collections.emptyList();
415             targetTypeBaseType = new BinaryType(bytes, lengths, null);
416         }
417         return targetTypeBaseType;
418     }
419
420     /**
421      * Pull restriction from base type and add them to given constraints
422      *
423      * @param referencedType
424      * @param constraints
425      */
426     private void mergeConstraints(TypeDefinition<?> referencedType,
427             TypeConstraints constraints) {
428
429         if (referencedType instanceof DecimalTypeDefinition) {
430             constraints.addRanges(((DecimalTypeDefinition) referencedType)
431                     .getRangeStatements());
432             constraints
433                     .setFractionDigits(((DecimalTypeDefinition) referencedType)
434                             .getFractionDigits());
435         } else if (referencedType instanceof IntegerTypeDefinition) {
436             constraints.addRanges(((IntegerTypeDefinition) referencedType)
437                     .getRangeStatements());
438         } else if (referencedType instanceof StringTypeDefinition) {
439             constraints.addPatterns(((StringTypeDefinition) referencedType)
440                     .getPatterns());
441             constraints.addLengths(((StringTypeDefinition) referencedType)
442                     .getLengthStatements());
443         } else if (referencedType instanceof BinaryTypeDefinition) {
444             constraints.addLengths(((BinaryTypeDefinition) referencedType)
445                     .getLengthConstraints());
446         }
447     }
448
449     /**
450      * Go through all augmentation definitions and resolve them. This means find
451      * referenced node and add child nodes to it.
452      *
453      * @param modules
454      *            all available modules
455      * @param module
456      *            current module
457      */
458     private void resolveAugments(
459             Map<String, TreeMap<Date, ModuleBuilder>> modules,
460             ModuleBuilder module) {
461         Set<AugmentationSchemaBuilder> augmentBuilders = module
462                 .getAddedAugments();
463
464         Set<AugmentationSchema> augments = new HashSet<AugmentationSchema>();
465         for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
466             SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
467             String prefix = null;
468             List<String> augmentTargetPath = new ArrayList<String>();
469
470             for (QName pathPart : augmentTargetSchemaPath.getPath()) {
471                 prefix = pathPart.getPrefix();
472                 augmentTargetPath.add(pathPart.getLocalName());
473             }
474             ModuleBuilder dependentModule = findDependentModule(modules,
475                     module, prefix);
476             augmentTargetPath.add(0, dependentModule.getName());
477
478             AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
479                     .getNode(augmentTargetPath);
480             AugmentationSchema result = augmentBuilder.build();
481             augmentTarget.addAugmentation(result);
482             fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget);
483             augments.add(result);
484         }
485         module.setAugmentations(augments);
486     }
487
488     /**
489      * Add all augment's child nodes to given target.
490      *
491      * @param augment
492      * @param target
493      */
494     private void fillAugmentTarget(AugmentationSchemaBuilder augment,
495             ChildNodeBuilder target) {
496         for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
497             builder.setAugmenting(true);
498             target.addChildNode(builder);
499         }
500     }
501
502     /**
503      * Go through identity statements defined in current module and resolve
504      * their 'base' statement if present.
505      *
506      * @param modules
507      *            all modules
508      * @param module
509      *            module being resolved
510      */
511     private void resolveIdentities(
512             Map<String, TreeMap<Date, ModuleBuilder>> modules,
513             ModuleBuilder module) {
514         Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
515         for (IdentitySchemaNodeBuilder identity : identities) {
516             String baseIdentityName = identity.getBaseIdentityName();
517             if (baseIdentityName != null) {
518                 String baseIdentityPrefix = null;
519                 String baseIdentityLocalName = null;
520                 if (baseIdentityName.contains(":")) {
521                     String[] splitted = baseIdentityName.split(":");
522                     baseIdentityPrefix = splitted[0];
523                     baseIdentityLocalName = splitted[1];
524                 } else {
525                     baseIdentityPrefix = module.getPrefix();
526                     baseIdentityLocalName = baseIdentityName;
527                 }
528                 ModuleBuilder dependentModule = findDependentModule(modules,
529                         module, baseIdentityPrefix);
530
531                 Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
532                         .getAddedIdentities();
533                 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
534                     if (idBuilder.getQName().getLocalName()
535                             .equals(baseIdentityLocalName)) {
536                         identity.setBaseIdentity(idBuilder);
537                     }
538                 }
539             }
540         }
541     }
542
543     /**
544      * Find dependent module based on given prefix
545      *
546      * @param modules
547      *            all available modules
548      * @param module
549      *            current module
550      * @param prefix
551      *            target module prefix
552      * @return
553      */
554     private ModuleBuilder findDependentModule(
555             Map<String, TreeMap<Date, ModuleBuilder>> modules,
556             ModuleBuilder module, String prefix) {
557         ModuleBuilder dependentModule = null;
558         Date dependentModuleRevision = null;
559
560         if (prefix.equals(module.getPrefix())) {
561             dependentModule = module;
562         } else {
563             ModuleImport dependentModuleImport = getModuleImport(module, prefix);
564             if (dependentModuleImport == null) {
565                 throw new YangParseException("No import found with prefix '"
566                         + prefix + "' in module " + module.getName() + "'.");
567             }
568             String dependentModuleName = dependentModuleImport.getModuleName();
569             dependentModuleRevision = dependentModuleImport.getRevision();
570
571             TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
572                     .get(dependentModuleName);
573             if (dependentModuleRevision == null) {
574                 dependentModule = moduleBuildersByRevision.lastEntry()
575                         .getValue();
576             } else {
577                 dependentModule = moduleBuildersByRevision
578                         .get(dependentModuleRevision);
579             }
580         }
581
582         if (dependentModule == null) {
583             throw new YangParseException(
584                     "Failed to find dependent module with prefix '" + prefix
585                             + "' and revision '" + dependentModuleRevision
586                             + "'.");
587         }
588         return dependentModule;
589     }
590
591     /**
592      * Get module import referenced by given prefix.
593      *
594      * @param builder
595      *            module to search
596      * @param prefix
597      *            prefix associated with import
598      * @return ModuleImport based on given prefix
599      */
600     private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
601         ModuleImport moduleImport = null;
602         for (ModuleImport mi : builder.getModuleImports()) {
603             if (mi.getPrefix().equals(prefix)) {
604                 moduleImport = mi;
605                 break;
606             }
607         }
608         return moduleImport;
609     }
610
611     private Date createEpochTime() {
612         Calendar c = Calendar.getInstance();
613         c.setTimeInMillis(0);
614         return c.getTime();
615     }
616
617     private static class SchemaContextImpl implements SchemaContext {
618         private final Set<Module> modules;
619
620         private SchemaContextImpl(Set<Module> modules) {
621             this.modules = modules;
622         }
623
624         @Override
625         public Set<DataSchemaNode> getDataDefinitions() {
626             final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
627             for (Module m : modules) {
628                 dataDefs.addAll(m.getChildNodes());
629             }
630             return dataDefs;
631         }
632
633         @Override
634         public Set<Module> getModules() {
635             return modules;
636         }
637
638         @Override
639         public Set<NotificationDefinition> getNotifications() {
640             final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
641             for (Module m : modules) {
642                 notifications.addAll(m.getNotifications());
643             }
644             return notifications;
645         }
646
647         @Override
648         public Set<RpcDefinition> getOperations() {
649             final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
650             for (Module m : modules) {
651                 rpcs.addAll(m.getRpcs());
652             }
653             return rpcs;
654         }
655
656         @Override
657         public Set<ExtensionDefinition> getExtensions() {
658             final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
659             for (Module m : modules) {
660                 extensions.addAll(m.getExtensionSchemaNodes());
661             }
662             return extensions;
663         }
664     }
665
666 }