2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.yang.parser.impl;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.InputStream;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedHashSet;
24 import java.util.List;
26 import java.util.NoSuchElementException;
28 import java.util.TreeMap;
30 import org.antlr.v4.runtime.ANTLRInputStream;
31 import org.antlr.v4.runtime.CommonTokenStream;
32 import org.antlr.v4.runtime.tree.ParseTree;
33 import org.antlr.v4.runtime.tree.ParseTreeWalker;
34 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
36 import org.opendaylight.controller.yang.common.QName;
37 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
38 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
39 import org.opendaylight.controller.yang.model.api.Module;
40 import org.opendaylight.controller.yang.model.api.ModuleImport;
41 import org.opendaylight.controller.yang.model.api.MustDefinition;
42 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
43 import org.opendaylight.controller.yang.model.api.RpcDefinition;
44 import org.opendaylight.controller.yang.model.api.SchemaContext;
45 import org.opendaylight.controller.yang.model.api.SchemaPath;
46 import org.opendaylight.controller.yang.model.api.TypeDefinition;
47 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
49 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
50 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
51 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
52 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
53 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
54 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
55 import org.opendaylight.controller.yang.model.util.ExtendedType;
56 import org.opendaylight.controller.yang.model.util.IdentityrefType;
57 import org.opendaylight.controller.yang.model.util.UnknownType;
58 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.Builder;
61 import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
63 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
64 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
65 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
66 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
74 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
75 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
76 import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder;
77 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
78 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
79 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
80 import org.opendaylight.controller.yang.parser.util.ParserUtils;
81 import org.opendaylight.controller.yang.parser.util.RefineHolder;
82 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
83 import org.opendaylight.controller.yang.parser.util.YangParseException;
84 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
88 public class YangParserImpl implements YangModelParser {
90 private static final Logger logger = LoggerFactory
91 .getLogger(YangParserImpl.class);
94 public Set<Module> parseYangModels(final List<File> yangFiles) {
95 if (yangFiles != null) {
96 final List<InputStream> inputStreams = new ArrayList<InputStream>();
98 for (final File yangFile : yangFiles) {
100 inputStreams.add(new FileInputStream(yangFile));
101 } catch (FileNotFoundException e) {
102 logger.warn("Exception while reading yang file: "
103 + yangFile.getName(), e);
106 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
107 return build(modules);
109 return Collections.emptySet();
113 public Set<Module> parseYangModelsFromStreams(
114 final List<InputStream> yangModelStreams) {
115 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
116 return build(modules);
120 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
121 return new SchemaContextImpl(modules);
124 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
125 final List<InputStream> yangFileStreams) {
126 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
127 final ParseTreeWalker walker = new ParseTreeWalker();
128 final List<ParseTree> trees = parseStreams(yangFileStreams);
129 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
132 new YangModelBasicValidator(walker).validate(trees);
134 YangParserListenerImpl yangModelParser = null;
135 for (int i = 0; i < trees.size(); i++) {
136 yangModelParser = new YangParserListenerImpl();
137 walker.walk(yangModelParser, trees.get(i));
138 builders[i] = yangModelParser.getModuleBuilder();
141 // module dependency graph sorted
142 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
144 for (ModuleBuilder builder : sorted) {
145 final String builderName = builder.getName();
146 Date builderRevision = builder.getRevision();
147 if (builderRevision == null) {
148 builderRevision = new Date(0L);
150 TreeMap<Date, ModuleBuilder> builderByRevision = modules
152 if (builderByRevision == null) {
153 builderByRevision = new TreeMap<Date, ModuleBuilder>();
155 builderByRevision.put(builderRevision, builder);
156 modules.put(builderName, builderByRevision);
161 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
162 final List<ParseTree> trees = new ArrayList<ParseTree>();
163 for (InputStream yangStream : yangStreams) {
164 trees.add(parseStream(yangStream));
169 private ParseTree parseStream(final InputStream yangStream) {
170 ParseTree result = null;
172 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
173 final YangLexer lexer = new YangLexer(input);
174 final CommonTokenStream tokens = new CommonTokenStream(lexer);
175 final YangParser parser = new YangParser(tokens);
176 result = parser.yang();
177 } catch (IOException e) {
178 logger.warn("Exception while reading yang file: " + yangStream, e);
183 private Set<Module> build(
184 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
185 // fix unresolved nodes
186 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
188 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
190 final ModuleBuilder moduleBuilder = childEntry.getValue();
191 fixUnresolvedNodes(modules, moduleBuilder);
194 resolveAugments(modules);
197 final Set<Module> result = new LinkedHashSet<Module>();
198 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
200 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
201 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
203 final ModuleBuilder moduleBuilder = childEntry.getValue();
204 final Module module = moduleBuilder.build();
205 modulesByRevision.put(childEntry.getKey(), module);
212 private void fixUnresolvedNodes(
213 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
214 final ModuleBuilder builder) {
215 resolveDirtyNodes(modules, builder);
216 resolveIdentities(modules, builder);
217 resolveUses(modules, builder);
218 resolveUnknownNodes(modules, builder);
222 * Search for dirty nodes (node which contains UnknownType) and resolve
226 * all available modules
230 private void resolveDirtyNodes(
231 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
232 final ModuleBuilder module) {
233 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
235 if (!dirtyNodes.isEmpty()) {
236 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
239 final TypeAwareBuilder nodeToResolve = entry.getValue();
240 // different handling for union types
241 if (nodeToResolve instanceof UnionTypeBuilder) {
242 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
243 final List<TypeDefinition<?>> unionTypes = union.getTypes();
244 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
245 for (TypeDefinition<?> td : unionTypes) {
246 if (td instanceof UnknownType) {
247 final UnknownType unknownType = (UnknownType) td;
248 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
249 nodeToResolve, unknownType, modules, module);
250 union.setType(resolvedType);
251 toRemove.add(unknownType);
254 unionTypes.removeAll(toRemove);
255 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
256 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
258 nodeToResolve.setType(new IdentityrefType(findFullQName(
259 modules, module, idref), idref.getPath()));
261 final TypeDefinitionBuilder resolvedType = resolveType(
262 nodeToResolve, modules, module);
263 nodeToResolve.setType(resolvedType);
269 private TypeDefinitionBuilder resolveType(
270 final TypeAwareBuilder typeToResolve,
271 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
272 final ModuleBuilder builder) {
273 final TypeConstraints constraints = new TypeConstraints();
275 final TypeDefinitionBuilder targetType = getTypedefBuilder(
276 typeToResolve, modules, builder);
277 final TypeConstraints tConstraints = findConstraints(typeToResolve,
278 constraints, modules, builder);
279 targetType.setRanges(tConstraints.getRange());
280 targetType.setLengths(tConstraints.getLength());
281 targetType.setPatterns(tConstraints.getPatterns());
282 targetType.setFractionDigits(tConstraints.getFractionDigits());
287 private TypeDefinitionBuilder resolveTypeUnion(
288 final TypeAwareBuilder typeToResolve,
289 final UnknownType unknownType,
290 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
291 final ModuleBuilder builder) {
292 final TypeConstraints constraints = new TypeConstraints();
294 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
295 unknownType, modules, builder);
296 final 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());
306 private TypeDefinitionBuilder getTypedefBuilder(
307 final TypeAwareBuilder nodeToResolve,
308 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
309 final ModuleBuilder builder) {
311 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
312 if (nodeToResolveBase != null
313 && !(nodeToResolveBase instanceof UnknownType)) {
314 return (TypeDefinitionBuilder) nodeToResolve;
317 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
318 final QName unknownTypeQName = unknownType.getQName();
320 // search for module which contains referenced typedef
321 final ModuleBuilder dependentModule = findDependentModule(modules,
322 builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
323 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
324 dependentModule, unknownTypeQName.getLocalName(),
325 builder.getName(), nodeToResolve.getLine());
327 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
328 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
329 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
330 lookedUpBuilderCopy, modules, dependentModule);
334 private TypeDefinitionBuilder getUnionBuilder(
335 final TypeAwareBuilder nodeToResolve,
336 final UnknownType unknownType,
337 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
338 final ModuleBuilder module) {
340 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
341 if (baseTypeToResolve != null
342 && !(baseTypeToResolve instanceof UnknownType)) {
343 return (TypeDefinitionBuilder) nodeToResolve;
346 final QName unknownTypeQName = unknownType.getQName();
347 // search for module which contains referenced typedef
348 final ModuleBuilder dependentModule = findDependentModule(modules,
349 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
350 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
351 dependentModule, unknownTypeQName.getLocalName(),
352 module.getName(), nodeToResolve.getLine());
354 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
355 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
356 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
357 lookedUpBuilderCopy, modules, dependentModule);
361 private TypeDefinitionBuilder copyTypedefBuilder(
362 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
363 if (old instanceof UnionTypeBuilder) {
364 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
365 final UnionTypeBuilder newUnion = new UnionTypeBuilder(
366 oldUnion.getActualPath(), oldUnion.getNamespace(),
367 oldUnion.getRevision(), old.getLine());
368 for (TypeDefinition<?> td : oldUnion.getTypes()) {
369 newUnion.setType(td);
371 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
372 newUnion.setType(copyTypedefBuilder(tdb, true));
377 final QName oldName = old.getQName();
378 final QName newName = new QName(oldName.getNamespace(),
379 oldName.getRevision(), oldName.getPrefix(),
380 oldName.getLocalName());
381 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName,
384 tdb.setRanges(old.getRanges());
385 tdb.setLengths(old.getLengths());
386 tdb.setPatterns(old.getPatterns());
387 tdb.setFractionDigits(old.getFractionDigits());
388 tdb.setPath(old.getPath());
390 final TypeDefinition<?> oldType = old.getType();
391 if (oldType == null) {
392 tdb.setType(old.getTypedef());
394 tdb.setType(oldType);
397 if (!seekByTypedefBuilder) {
398 tdb.setDescription(old.getDescription());
399 tdb.setReference(old.getReference());
400 tdb.setStatus(old.getStatus());
401 tdb.setDefaultValue(old.getDefaultValue());
402 tdb.setUnits(old.getUnits());
407 private TypeDefinitionBuilder resolveCopiedBuilder(
408 final TypeDefinitionBuilder copy,
409 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
410 final ModuleBuilder builder) {
412 if (copy instanceof UnionTypeBuilder) {
413 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
414 final List<TypeDefinition<?>> unionTypes = union.getTypes();
415 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
416 for (TypeDefinition<?> td : unionTypes) {
417 if (td instanceof UnknownType) {
418 final UnknownType unknownType = (UnknownType) td;
419 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
420 union, unknownType, modules, builder);
421 union.setType(resolvedType);
422 toRemove.add(unknownType);
425 unionTypes.removeAll(toRemove);
430 final TypeDefinition<?> base = copy.getType();
431 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
432 if (base != null && !(base instanceof UnknownType)) {
434 } else if (base instanceof UnknownType) {
435 final UnknownType unknownType = (UnknownType) base;
436 final QName unknownTypeQName = unknownType.getQName();
437 final String unknownTypePrefix = unknownTypeQName.getPrefix();
438 final ModuleBuilder dependentModule = findDependentModule(modules,
439 builder, unknownTypePrefix, copy.getLine());
440 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
441 modules, dependentModule);
442 copy.setType(utBuilder);
444 } else if (base == null && baseTdb != null) {
445 // make a copy of baseTypeDef and call again
446 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
448 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
449 baseTdbCopy, modules, builder);
450 copy.setType(baseTdbCopyResolved);
453 throw new IllegalStateException("Failed to resolve type "
454 + copy.getQName().getLocalName());
458 private TypeDefinitionBuilder findTypedefBuilder(
459 final QName unknownTypeQName,
460 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
461 final ModuleBuilder builder, int line) {
462 // search for module which contains referenced typedef
463 final ModuleBuilder dependentModule = findDependentModule(modules,
464 builder, unknownTypeQName.getPrefix(), line);
465 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
466 dependentModule, unknownTypeQName.getLocalName(),
467 builder.getName(), line);
468 return copyTypedefBuilder(lookedUpBuilder, true);
471 private TypeConstraints findConstraints(
472 final TypeAwareBuilder nodeToResolve,
473 final TypeConstraints constraints,
474 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
475 final ModuleBuilder builder) {
476 // union type cannot be restricted
477 if (nodeToResolve instanceof UnionTypeBuilder) {
481 // if referenced type is UnknownType again, search recursively with
482 // current constraints
483 final TypeDefinition<?> referencedType = nodeToResolve.getType();
484 List<RangeConstraint> ranges = Collections.emptyList();
485 List<LengthConstraint> lengths = Collections.emptyList();
486 List<PatternConstraint> patterns = Collections.emptyList();
487 Integer fractionDigits = null;
488 if (referencedType == null) {
489 final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef();
490 ranges = tdb.getRanges();
491 constraints.addRanges(ranges);
492 lengths = tdb.getLengths();
493 constraints.addLengths(lengths);
494 patterns = tdb.getPatterns();
495 constraints.addPatterns(patterns);
496 fractionDigits = tdb.getFractionDigits();
497 constraints.setFractionDigits(fractionDigits);
499 } else if (referencedType instanceof ExtendedType) {
500 final ExtendedType ext = (ExtendedType) referencedType;
501 ranges = ext.getRanges();
502 constraints.addRanges(ranges);
503 lengths = ext.getLengths();
504 constraints.addLengths(lengths);
505 patterns = ext.getPatterns();
506 constraints.addPatterns(patterns);
507 fractionDigits = ext.getFractionDigits();
508 constraints.setFractionDigits(fractionDigits);
509 return findConstraints(
510 findTypedefBuilder(ext.getQName(), modules, builder,
511 nodeToResolve.getLine()), constraints, modules,
513 } else if (referencedType instanceof UnknownType) {
514 final UnknownType unknown = (UnknownType) referencedType;
515 ranges = unknown.getRangeStatements();
516 constraints.addRanges(ranges);
517 lengths = unknown.getLengthStatements();
518 constraints.addLengths(lengths);
519 patterns = unknown.getPatterns();
520 constraints.addPatterns(patterns);
521 fractionDigits = unknown.getFractionDigits();
522 constraints.setFractionDigits(fractionDigits);
524 String unknownTypePrefix = unknown.getQName().getPrefix();
525 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
526 unknownTypePrefix = builder.getPrefix();
528 final ModuleBuilder dependentModule = findDependentModule(modules,
529 builder, unknown.getQName().getPrefix(),
530 nodeToResolve.getLine());
531 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
532 unknown.getQName(), modules, builder,
533 nodeToResolve.getLine());
534 return findConstraints(utBuilder, constraints, modules,
537 // HANDLE BASE YANG TYPE
538 mergeConstraints(referencedType, constraints);
544 * Go through all typedef statements from given module and search for one
548 * typedef statements to search
550 * name of searched typedef
551 * @return typedef with name equals to given name
553 private TypeDefinitionBuilder findTypedefBuilderByName(
554 final ModuleBuilder dependentModule, final String name,
555 final String currentModuleName, final int line) {
556 TypeDefinitionBuilder result = null;
557 final Set<TypeDefinitionBuilder> typedefs = dependentModule
558 .getModuleTypedefs();
559 for (TypeDefinitionBuilder td : typedefs) {
560 if (td.getQName().getLocalName().equals(name)) {
565 if (result == null) {
566 throw new YangParseException(currentModuleName, line,
567 "Target module '" + dependentModule.getName()
568 + "' does not contain typedef '" + name + "'.");
574 * Pull restriction from referenced type and add them to given constraints
576 * @param referencedType
579 private void mergeConstraints(final TypeDefinition<?> referencedType,
580 final TypeConstraints constraints) {
582 if (referencedType instanceof DecimalTypeDefinition) {
583 constraints.addRanges(((DecimalTypeDefinition) referencedType)
584 .getRangeStatements());
586 .setFractionDigits(((DecimalTypeDefinition) referencedType)
587 .getFractionDigits());
588 } else if (referencedType instanceof IntegerTypeDefinition) {
589 constraints.addRanges(((IntegerTypeDefinition) referencedType)
590 .getRangeStatements());
591 } else if (referencedType instanceof StringTypeDefinition) {
592 constraints.addPatterns(((StringTypeDefinition) referencedType)
594 constraints.addLengths(((StringTypeDefinition) referencedType)
595 .getLengthStatements());
596 } else if (referencedType instanceof BinaryTypeDefinition) {
597 constraints.addLengths(((BinaryTypeDefinition) referencedType)
598 .getLengthConstraints());
603 * Go through all augmentation definitions and resolve them. This method
604 * also finds referenced node and add child nodes to it.
607 * all available modules
609 private void resolveAugments(
610 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
611 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
612 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
613 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
615 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
617 allModulesList.add(inner.getValue());
618 allModulesSet.add(inner.getValue());
622 for (int i = 0; i < allModulesList.size(); i++) {
623 final ModuleBuilder module = allModulesList.get(i);
624 // try to resolve augments in module
625 resolveAugment(modules, module);
626 // while all augments are not resolved
627 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
629 while (!(module.getAugmentsResolved() == module.getAddedAugments()
631 ModuleBuilder nextModule = null;
632 // try resolve other module augments
634 nextModule = allModulesIterator.next();
635 resolveAugment(modules, nextModule);
636 } catch (NoSuchElementException e) {
637 throw new YangParseException(
638 "Failed to resolve augments in module '"
639 + module.getName() + "'.", e);
641 // then try to resolve first module again
642 resolveAugment(modules, module);
650 * all available modules
654 private void resolveAugment(
655 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
656 final ModuleBuilder module) {
657 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
658 for (AugmentationSchemaBuilder augmentBuilder : module
659 .getAddedAugments()) {
661 if (!augmentBuilder.isResolved()) {
662 final SchemaPath augmentTargetSchemaPath = augmentBuilder
664 final List<QName> path = augmentTargetSchemaPath.getPath();
667 final QName qname = path.get(i);
668 String prefix = qname.getPrefix();
669 if (prefix == null) {
670 prefix = module.getPrefix();
673 DataSchemaNodeBuilder currentParent = null;
674 final ModuleBuilder dependentModule = findDependentModule(
675 modules, module, prefix, augmentBuilder.getLine());
676 for (DataSchemaNodeBuilder child : dependentModule
678 final QName childQName = child.getQName();
679 if (childQName.getLocalName().equals(
680 qname.getLocalName())) {
681 currentParent = child;
687 for (; i < path.size(); i++) {
688 final QName currentQName = path.get(i);
689 DataSchemaNodeBuilder newParent = null;
690 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
692 final QName childQName = child.getQName();
693 if (childQName.getLocalName().equals(
694 currentQName.getLocalName())) {
699 if (newParent == null) {
700 break; // node not found, quit search
702 currentParent = newParent;
706 final QName currentQName = currentParent.getQName();
707 final QName lastAugmentPathElement = path
708 .get(path.size() - 1);
709 if (currentQName.getLocalName().equals(
710 lastAugmentPathElement.getLocalName())) {
711 ParserUtils.fillAugmentTarget(augmentBuilder,
712 (ChildNodeBuilder) currentParent);
713 ((AugmentationTargetBuilder) currentParent)
714 .addAugmentation(augmentBuilder);
715 SchemaPath oldPath = currentParent.getPath();
716 augmentBuilder.setTargetPath(new SchemaPath(oldPath
717 .getPath(), oldPath.isAbsolute()));
718 augmentBuilder.setResolved(true);
719 module.augmentResolved();
728 * Go through identity statements defined in current module and resolve
729 * their 'base' statement if present.
734 * module being resolved
736 private void resolveIdentities(
737 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
738 final ModuleBuilder module) {
739 final Set<IdentitySchemaNodeBuilder> identities = module
740 .getAddedIdentities();
741 for (IdentitySchemaNodeBuilder identity : identities) {
742 final String baseIdentityName = identity.getBaseIdentityName();
743 if (baseIdentityName != null) {
744 String baseIdentityPrefix = null;
745 String baseIdentityLocalName = null;
746 if (baseIdentityName.contains(":")) {
747 final String[] splitted = baseIdentityName.split(":");
748 baseIdentityPrefix = splitted[0];
749 baseIdentityLocalName = splitted[1];
751 baseIdentityPrefix = module.getPrefix();
752 baseIdentityLocalName = baseIdentityName;
754 final ModuleBuilder dependentModule = findDependentModule(
755 modules, module, baseIdentityPrefix, identity.getLine());
757 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
758 .getAddedIdentities();
759 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
760 if (idBuilder.getQName().getLocalName()
761 .equals(baseIdentityLocalName)) {
762 identity.setBaseIdentity(idBuilder);
770 * Go through uses statements defined in current module and resolve their
776 * module being resolved
778 private void resolveUses(
779 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
780 final ModuleBuilder module) {
781 final Map<List<String>, UsesNodeBuilder> moduleUses = module
782 .getAddedUsesNodes();
783 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
785 final List<String> key = entry.getKey();
786 final UsesNodeBuilder usesNode = entry.getValue();
788 final String groupingName = key.get(key.size() - 1);
790 for (RefineHolder refine : usesNode.getRefines()) {
792 final String defaultStr = refine.getDefaultStr();
793 final Boolean mandatory = refine.isMandatory();
794 final MustDefinition must = refine.getMust();
795 final Boolean presence = refine.isPresence();
796 final Integer min = refine.getMinElements();
797 final Integer max = refine.getMaxElements();
798 final List<UnknownSchemaNodeBuilder> unknownNodes = refine
801 Builder refineTarget = getRefineTargetBuilder(groupingName,
802 refine, modules, module);
803 if (refineTarget instanceof LeafSchemaNodeBuilder) {
804 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
805 if (defaultStr != null && !("".equals(defaultStr))) {
806 leaf.setDefaultStr(defaultStr);
808 if (mandatory != null) {
809 leaf.getConstraints().setMandatory(mandatory);
812 leaf.getConstraints().addMustDefinition(must);
814 if (unknownNodes != null) {
815 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
816 leaf.addUnknownSchemaNode(unknown);
819 usesNode.addRefineNode(leaf);
820 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
821 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
822 if (presence != null) {
823 container.setPresence(presence);
826 container.getConstraints().addMustDefinition(must);
828 if (unknownNodes != null) {
829 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
830 container.addUnknownSchemaNode(unknown);
833 usesNode.addRefineNode(container);
834 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
835 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
837 list.getConstraints().addMustDefinition(must);
840 list.getConstraints().setMinElements(min);
843 list.getConstraints().setMaxElements(max);
845 if (unknownNodes != null) {
846 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
847 list.addUnknownSchemaNode(unknown);
850 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
851 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
852 groupingName, refine, modules, module);
854 leafList.getConstraints().addMustDefinition(must);
857 leafList.getConstraints().setMinElements(min);
860 leafList.getConstraints().setMaxElements(max);
862 if (unknownNodes != null) {
863 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
864 leafList.addUnknownSchemaNode(unknown);
867 } else if (refineTarget instanceof ChoiceBuilder) {
868 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
869 if (defaultStr != null) {
870 choice.setDefaultCase(defaultStr);
872 if (mandatory != null) {
873 choice.getConstraints().setMandatory(mandatory);
875 if (unknownNodes != null) {
876 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
877 choice.addUnknownSchemaNode(unknown);
880 } else if (refineTarget instanceof AnyXmlBuilder) {
881 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
882 if (mandatory != null) {
883 anyXml.getConstraints().setMandatory(mandatory);
886 anyXml.getConstraints().addMustDefinition(must);
888 if (unknownNodes != null) {
889 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
890 anyXml.addUnknownSchemaNode(unknown);
899 * Find original builder of refine node and return copy of this builder.
901 * @param groupingPath
902 * path to grouping which contains node to refine
904 * refine object containing informations about refine
909 * @return copy of Builder object of node to be refined if it is present in
910 * grouping, null otherwise
912 private Builder getRefineTargetBuilder(final String groupingPath,
913 final RefineHolder refine,
914 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
915 final ModuleBuilder module) {
916 Builder result = null;
917 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
918 refine, modules, module);
919 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
921 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
922 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
924 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
925 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
927 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
928 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
930 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
931 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
933 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
934 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
936 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
938 throw new YangParseException(module.getName(), refine.getLine(),
939 "Target '" + refine.getName() + "' can not be refined");
945 * Find builder of refine node.
947 * @param groupingPath
948 * path to grouping which contains node to refine
949 * @param refineNodeName
950 * name of node to be refined
955 * @return Builder object of refine node if it is present in grouping, null
958 private Builder findRefineTargetBuilder(final String groupingPath,
959 final RefineHolder refine,
960 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
961 final ModuleBuilder module) {
962 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
963 final List<String> builderPath = new ArrayList<String>();
964 String prefix = null;
965 for (QName qname : path.getPath()) {
966 builderPath.add(qname.getLocalName());
967 prefix = qname.getPrefix();
969 if (prefix == null) {
970 prefix = module.getPrefix();
973 final ModuleBuilder dependentModule = findDependentModule(modules,
974 module, prefix, refine.getLine());
975 builderPath.add(0, "grouping");
976 builderPath.add(0, dependentModule.getName());
977 final GroupingBuilder builder = (GroupingBuilder) dependentModule
978 .getNode(builderPath);
980 return builder.getChildNode(refine.getName());
983 private QName findFullQName(
984 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
985 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
987 String baseString = idref.getBaseString();
988 if (baseString.contains(":")) {
989 String[] splittedBase = baseString.split(":");
990 if (splittedBase.length > 2) {
991 throw new YangParseException(module.getName(), idref.getLine(),
992 "Failed to parse identityref base: " + baseString);
994 String prefix = splittedBase[0];
995 String name = splittedBase[1];
996 ModuleBuilder dependentModule = findDependentModule(modules,
997 module, prefix, idref.getLine());
998 result = new QName(dependentModule.getNamespace(),
999 dependentModule.getRevision(), prefix, name);
1001 result = new QName(module.getNamespace(), module.getRevision(),
1002 module.getPrefix(), baseString);
1007 private void resolveUnknownNodes(
1008 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1009 final ModuleBuilder module) {
1010 for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
1011 QName nodeType = usnb.getNodeType();
1012 if (nodeType.getNamespace() == null
1013 || nodeType.getRevision() == null) {
1015 ModuleBuilder dependentModule = findDependentModule(
1016 modules, module, nodeType.getPrefix(),
1018 QName newNodeType = new QName(
1019 dependentModule.getNamespace(),
1020 dependentModule.getRevision(),
1021 nodeType.getPrefix(), nodeType.getLocalName());
1022 usnb.setNodeType(newNodeType);
1023 } catch (YangParseException e) {
1024 logger.debug(module.getName(), usnb.getLine(),
1025 "Failed to find unknown node type: " + nodeType);
1032 * Find dependent module based on given prefix
1035 * all available modules
1039 * target module prefix
1042 private ModuleBuilder findDependentModule(
1043 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1044 final ModuleBuilder module, final String prefix, final int line) {
1045 ModuleBuilder dependentModule = null;
1046 Date dependentModuleRevision = null;
1048 if (prefix.equals(module.getPrefix())) {
1049 dependentModule = module;
1051 final ModuleImport dependentModuleImport = ParserUtils
1052 .getModuleImport(module, prefix);
1053 if (dependentModuleImport == null) {
1054 throw new YangParseException(module.getName(), line,
1055 "No import found with prefix '" + prefix + "'.");
1057 final String dependentModuleName = dependentModuleImport
1059 dependentModuleRevision = dependentModuleImport.getRevision();
1061 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1062 .get(dependentModuleName);
1063 if (moduleBuildersByRevision == null) {
1064 throw new YangParseException(module.getName(), line,
1065 "Failed to find dependent module '"
1066 + dependentModuleName + "'.");
1068 if (dependentModuleRevision == null) {
1069 dependentModule = moduleBuildersByRevision.lastEntry()
1072 dependentModule = moduleBuildersByRevision
1073 .get(dependentModuleRevision);
1077 if (dependentModule == null) {
1078 throw new YangParseException(module.getName(), line,
1079 "Failed to find dependent module with prefix '" + prefix
1080 + "' and revision '" + dependentModuleRevision
1083 return dependentModule;
1086 private static class SchemaContextImpl implements SchemaContext {
1087 private final Set<Module> modules;
1089 private SchemaContextImpl(final Set<Module> modules) {
1090 this.modules = modules;
1094 public Set<DataSchemaNode> getDataDefinitions() {
1095 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
1096 for (Module m : modules) {
1097 dataDefs.addAll(m.getChildNodes());
1103 public Set<Module> getModules() {
1108 public Set<NotificationDefinition> getNotifications() {
1109 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
1110 for (Module m : modules) {
1111 notifications.addAll(m.getNotifications());
1113 return notifications;
1117 public Set<RpcDefinition> getOperations() {
1118 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
1119 for (Module m : modules) {
1120 rpcs.addAll(m.getRpcs());
1126 public Set<ExtensionDefinition> getExtensions() {
1127 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
1128 for (Module m : modules) {
1129 extensions.addAll(m.getExtensionSchemaNodes());
1135 public Module findModuleByName(final String name, final Date revision) {
1137 for (final Module module : modules) {
1138 if (revision == null) {
1139 if (module.getName().equals(name)) {
1142 } else if (module.getName().equals(name)
1143 && module.getRevision().equals(revision)) {
1152 public Module findModuleByNamespace(final URI namespace) {
1153 if (namespace != null) {
1154 for (final Module module : modules) {
1155 if (module.getNamespace().equals(namespace)) {