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