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.model.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.List;
24 import java.util.NoSuchElementException;
26 import java.util.TreeMap;
28 import org.antlr.v4.runtime.ANTLRInputStream;
29 import org.antlr.v4.runtime.CommonTokenStream;
30 import org.antlr.v4.runtime.tree.ParseTree;
31 import org.antlr.v4.runtime.tree.ParseTreeWalker;
32 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
34 import org.opendaylight.controller.yang.common.QName;
35 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
36 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
37 import org.opendaylight.controller.yang.model.api.Module;
38 import org.opendaylight.controller.yang.model.api.ModuleImport;
39 import org.opendaylight.controller.yang.model.api.MustDefinition;
40 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
41 import org.opendaylight.controller.yang.model.api.RpcDefinition;
42 import org.opendaylight.controller.yang.model.api.SchemaContext;
43 import org.opendaylight.controller.yang.model.api.SchemaPath;
44 import org.opendaylight.controller.yang.model.api.TypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
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.Builder;
56 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;
62 import org.opendaylight.controller.yang.model.parser.builder.impl.AnyXmlBuilder;
63 import org.opendaylight.controller.yang.model.parser.builder.impl.ChoiceBuilder;
64 import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchemaNodeBuilder;
65 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
66 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentityrefTypeBuilder;
67 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
68 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
69 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
70 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
71 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
72 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
73 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
74 import org.opendaylight.controller.yang.model.parser.util.ParserUtils;
75 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
76 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
77 import org.opendaylight.controller.yang.model.parser.util.YangParseException;
78 import org.opendaylight.controller.yang.model.util.ExtendedType;
79 import org.opendaylight.controller.yang.model.util.IdentityrefType;
80 import org.opendaylight.controller.yang.model.util.UnknownType;
81 import org.opendaylight.controller.yang.model.validator.YangModelBasicValidator;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
85 public class YangModelParserImpl implements YangModelParser {
87 private static final Logger logger = LoggerFactory
88 .getLogger(YangModelParserImpl.class);
91 public Set<Module> parseYangModels(final List<File> yangFiles) {
92 if (yangFiles != null) {
93 final List<InputStream> inputStreams = new ArrayList<InputStream>();
95 for (final File yangFile : yangFiles) {
97 inputStreams.add(new FileInputStream(yangFile));
98 } catch (FileNotFoundException e) {
99 logger.warn("Exception while reading yang file: "
100 + yangFile.getName(), e);
103 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
104 return build(modules);
106 return Collections.emptySet();
110 public Set<Module> parseYangModelsFromStreams(
111 final List<InputStream> yangModelStreams) {
112 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
113 return build(modules);
117 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
118 return new SchemaContextImpl(modules);
121 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
122 final List<InputStream> yangFileStreams) {
123 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
124 final ParseTreeWalker walker = new ParseTreeWalker();
125 final List<ParseTree> trees = parseStreams(yangFileStreams);
126 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
129 new YangModelBasicValidator(walker).validate(trees);
131 YangModelParserListenerImpl yangModelParser = null;
132 for (int i = 0; i < trees.size(); i++) {
133 yangModelParser = new YangModelParserListenerImpl();
134 walker.walk(yangModelParser, trees.get(i));
135 builders[i] = yangModelParser.getModuleBuilder();
138 for (ModuleBuilder builder : builders) {
139 final String builderName = builder.getName();
140 Date builderRevision = builder.getRevision();
141 if (builderRevision == null) {
142 builderRevision = new Date(0L);
144 TreeMap<Date, ModuleBuilder> builderByRevision = modules
146 if (builderByRevision == null) {
147 builderByRevision = new TreeMap<Date, ModuleBuilder>();
149 builderByRevision.put(builderRevision, builder);
150 modules.put(builderName, builderByRevision);
155 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
156 final List<ParseTree> trees = new ArrayList<ParseTree>();
157 for (InputStream yangStream : yangStreams) {
158 trees.add(parseStream(yangStream));
163 private ParseTree parseStream(final InputStream yangStream) {
164 ParseTree result = null;
166 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
167 final YangLexer lexer = new YangLexer(input);
168 final CommonTokenStream tokens = new CommonTokenStream(lexer);
169 final YangParser parser = new YangParser(tokens);
170 result = parser.yang();
171 } catch (IOException e) {
172 logger.warn("Exception while reading yang file: " + yangStream, e);
177 private Set<Module> build(
178 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
179 // fix unresolved nodes
180 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
182 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
184 final ModuleBuilder moduleBuilder = childEntry.getValue();
185 fixUnresolvedNodes(modules, moduleBuilder);
188 resolveAugments(modules);
191 final Set<Module> result = new HashSet<Module>();
192 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
194 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
195 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
197 final ModuleBuilder moduleBuilder = childEntry.getValue();
198 final Module module = moduleBuilder.build();
199 modulesByRevision.put(childEntry.getKey(), module);
206 private void fixUnresolvedNodes(
207 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
208 final ModuleBuilder builder) {
209 resolveDirtyNodes(modules, builder);
210 resolveIdentities(modules, builder);
211 resolveUses(modules, builder);
212 resolveUnknownNodes(modules, builder);
216 * Search for dirty nodes (node which contains UnknownType) and resolve
220 * all available modules
224 private void resolveDirtyNodes(
225 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
226 final ModuleBuilder module) {
227 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
229 if (!dirtyNodes.isEmpty()) {
230 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
233 final TypeAwareBuilder nodeToResolve = entry.getValue();
234 // different handling for union types
235 if (nodeToResolve instanceof UnionTypeBuilder) {
236 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
237 final List<TypeDefinition<?>> unionTypes = union.getTypes();
238 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
239 for (TypeDefinition<?> td : unionTypes) {
240 if (td instanceof UnknownType) {
241 final UnknownType unknownType = (UnknownType) td;
242 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
243 nodeToResolve, unknownType, modules, module);
244 union.setType(resolvedType);
245 toRemove.add(unknownType);
248 unionTypes.removeAll(toRemove);
249 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
250 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
252 nodeToResolve.setType(new IdentityrefType(findFullQName(
253 modules, module, idref), idref.getPath()));
255 final TypeDefinitionBuilder resolvedType = resolveType(
256 nodeToResolve, modules, module);
257 nodeToResolve.setType(resolvedType);
263 private TypeDefinitionBuilder resolveType(
264 final TypeAwareBuilder typeToResolve,
265 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
266 final ModuleBuilder builder) {
267 final TypeConstraints constraints = new TypeConstraints();
269 final TypeDefinitionBuilder targetType = getTypedefBuilder(
270 typeToResolve, modules, builder);
271 final TypeConstraints tConstraints = findConstraints(typeToResolve,
272 constraints, modules, builder);
273 targetType.setRanges(tConstraints.getRange());
274 targetType.setLengths(tConstraints.getLength());
275 targetType.setPatterns(tConstraints.getPatterns());
276 targetType.setFractionDigits(tConstraints.getFractionDigits());
281 private TypeDefinitionBuilder resolveTypeUnion(
282 final TypeAwareBuilder typeToResolve,
283 final UnknownType unknownType,
284 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
285 final ModuleBuilder builder) {
286 final TypeConstraints constraints = new TypeConstraints();
288 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
289 unknownType, modules, builder);
290 final TypeConstraints tConstraints = findConstraints(typeToResolve,
291 constraints, modules, builder);
292 targetType.setRanges(tConstraints.getRange());
293 targetType.setLengths(tConstraints.getLength());
294 targetType.setPatterns(tConstraints.getPatterns());
295 targetType.setFractionDigits(tConstraints.getFractionDigits());
300 private TypeDefinitionBuilder getTypedefBuilder(
301 final TypeAwareBuilder nodeToResolve,
302 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
303 final ModuleBuilder builder) {
305 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
306 if (nodeToResolveBase != null
307 && !(nodeToResolveBase instanceof UnknownType)) {
308 return (TypeDefinitionBuilder) nodeToResolve;
311 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
312 final QName unknownTypeQName = unknownType.getQName();
314 // search for module which contains referenced typedef
315 final ModuleBuilder dependentModule = findDependentModule(modules,
316 builder, unknownTypeQName.getPrefix());
317 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
318 dependentModule, unknownTypeQName.getLocalName());
320 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
321 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
322 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
323 lookedUpBuilderCopy, modules, dependentModule);
327 private TypeDefinitionBuilder getUnionBuilder(
328 final TypeAwareBuilder nodeToResolve,
329 final UnknownType unknownType,
330 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
331 final ModuleBuilder module) {
333 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
334 if (baseTypeToResolve != null
335 && !(baseTypeToResolve instanceof UnknownType)) {
336 return (TypeDefinitionBuilder) nodeToResolve;
339 final QName unknownTypeQName = unknownType.getQName();
340 // search for module which contains referenced typedef
341 final ModuleBuilder dependentModule = findDependentModule(modules,
342 module, unknownTypeQName.getPrefix());
343 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
344 dependentModule, unknownTypeQName.getLocalName());
346 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
347 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
348 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
349 lookedUpBuilderCopy, modules, dependentModule);
353 private TypeDefinitionBuilder copyTypedefBuilder(
354 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
355 if (old instanceof UnionTypeBuilder) {
356 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
357 final UnionTypeBuilder newUnion = new UnionTypeBuilder(
358 oldUnion.getActualPath(), oldUnion.getNamespace(),
359 oldUnion.getRevision());
360 for (TypeDefinition<?> td : oldUnion.getTypes()) {
361 newUnion.setType(td);
363 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
364 newUnion.setType(copyTypedefBuilder(tdb, true));
369 final QName oldName = old.getQName();
370 final QName newName = new QName(oldName.getNamespace(),
371 oldName.getRevision(), oldName.getPrefix(),
372 oldName.getLocalName());
373 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName);
375 tdb.setRanges(old.getRanges());
376 tdb.setLengths(old.getLengths());
377 tdb.setPatterns(old.getPatterns());
378 tdb.setFractionDigits(old.getFractionDigits());
379 tdb.setPath(old.getPath());
381 final TypeDefinition<?> oldType = old.getType();
382 if (oldType == null) {
383 tdb.setType(old.getTypedef());
385 tdb.setType(oldType);
388 if (!seekByTypedefBuilder) {
389 tdb.setDescription(old.getDescription());
390 tdb.setReference(old.getReference());
391 tdb.setStatus(old.getStatus());
392 tdb.setDefaultValue(old.getDefaultValue());
393 tdb.setUnits(old.getUnits());
398 private TypeDefinitionBuilder resolveCopiedBuilder(
399 final TypeDefinitionBuilder copy,
400 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
401 final ModuleBuilder builder) {
403 if (copy instanceof UnionTypeBuilder) {
404 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
405 final List<TypeDefinition<?>> unionTypes = union.getTypes();
406 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
407 for (TypeDefinition<?> td : unionTypes) {
408 if (td instanceof UnknownType) {
409 final UnknownType unknownType = (UnknownType) td;
410 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
411 union, unknownType, modules, builder);
412 union.setType(resolvedType);
413 toRemove.add(unknownType);
416 unionTypes.removeAll(toRemove);
421 final TypeDefinition<?> base = copy.getType();
422 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
423 if (base != null && !(base instanceof UnknownType)) {
425 } else if (base instanceof UnknownType) {
426 final UnknownType unknownType = (UnknownType) base;
427 final QName unknownTypeQName = unknownType.getQName();
428 final String unknownTypePrefix = unknownTypeQName.getPrefix();
429 final ModuleBuilder dependentModule = findDependentModule(modules,
430 builder, unknownTypePrefix);
431 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
432 modules, dependentModule);
433 copy.setType(utBuilder);
435 } else if (base == null && baseTdb != null) {
436 // make a copy of baseTypeDef and call again
437 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
439 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
440 baseTdbCopy, modules, builder);
441 copy.setType(baseTdbCopyResolved);
444 throw new IllegalStateException("Failed to resolve type "
445 + copy.getQName().getLocalName());
449 private TypeDefinitionBuilder findTypedefBuilder(
450 final QName unknownTypeQName,
451 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
452 final ModuleBuilder builder) {
453 // search for module which contains referenced typedef
454 final ModuleBuilder dependentModule = findDependentModule(modules,
455 builder, unknownTypeQName.getPrefix());
456 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
457 dependentModule, unknownTypeQName.getLocalName());
458 return copyTypedefBuilder(lookedUpBuilder, true);
461 private TypeConstraints findConstraints(
462 final TypeAwareBuilder nodeToResolve,
463 final TypeConstraints constraints,
464 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
465 final ModuleBuilder builder) {
466 // union type cannot be restricted
467 if (nodeToResolve instanceof UnionTypeBuilder) {
471 // if referenced type is UnknownType again, search recursively with
472 // current constraints
473 final TypeDefinition<?> referencedType = nodeToResolve.getType();
474 List<RangeConstraint> ranges = Collections.emptyList();
475 List<LengthConstraint> lengths = Collections.emptyList();
476 List<PatternConstraint> patterns = Collections.emptyList();
477 Integer fractionDigits = null;
478 if (referencedType == null) {
479 final TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
480 ranges = tdb.getRanges();
481 constraints.addRanges(ranges);
482 lengths = tdb.getLengths();
483 constraints.addLengths(lengths);
484 patterns = tdb.getPatterns();
485 constraints.addPatterns(patterns);
486 fractionDigits = tdb.getFractionDigits();
487 constraints.setFractionDigits(fractionDigits);
489 } else if (referencedType instanceof ExtendedType) {
490 final ExtendedType ext = (ExtendedType) referencedType;
491 ranges = ext.getRanges();
492 constraints.addRanges(ranges);
493 lengths = ext.getLengths();
494 constraints.addLengths(lengths);
495 patterns = ext.getPatterns();
496 constraints.addPatterns(patterns);
497 fractionDigits = ext.getFractionDigits();
498 constraints.setFractionDigits(fractionDigits);
499 return findConstraints(
500 findTypedefBuilder(ext.getQName(), modules, builder),
501 constraints, modules, builder);
502 } else if (referencedType instanceof UnknownType) {
503 final UnknownType unknown = (UnknownType) referencedType;
504 ranges = unknown.getRangeStatements();
505 constraints.addRanges(ranges);
506 lengths = unknown.getLengthStatements();
507 constraints.addLengths(lengths);
508 patterns = unknown.getPatterns();
509 constraints.addPatterns(patterns);
510 fractionDigits = unknown.getFractionDigits();
511 constraints.setFractionDigits(fractionDigits);
513 String unknownTypePrefix = unknown.getQName().getPrefix();
514 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
515 unknownTypePrefix = builder.getPrefix();
517 final ModuleBuilder dependentModule = findDependentModule(modules,
518 builder, unknown.getQName().getPrefix());
519 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
520 unknown.getQName(), modules, builder);
521 return findConstraints(utBuilder, constraints, modules,
524 // HANDLE BASE YANG TYPE
525 mergeConstraints(referencedType, constraints);
531 * Go through all typedef statements from given module and search for one
535 * typedef statements to search
537 * name of searched typedef
538 * @return typedef with name equals to given name
540 private TypeDefinitionBuilder findTypedefBuilderByName(
541 final ModuleBuilder dependentModule, final String name) {
542 TypeDefinitionBuilder result = null;
543 final Set<TypeDefinitionBuilder> typedefs = dependentModule
544 .getModuleTypedefs();
545 for (TypeDefinitionBuilder td : typedefs) {
546 if (td.getQName().getLocalName().equals(name)) {
551 if (result == null) {
552 throw new YangParseException("Target module '"
553 + dependentModule.getName()
554 + "' does not contain typedef '" + name + "'.");
560 * Pull restriction from referenced type and add them to given constraints
562 * @param referencedType
565 private void mergeConstraints(final TypeDefinition<?> referencedType,
566 final TypeConstraints constraints) {
568 if (referencedType instanceof DecimalTypeDefinition) {
569 constraints.addRanges(((DecimalTypeDefinition) referencedType)
570 .getRangeStatements());
572 .setFractionDigits(((DecimalTypeDefinition) referencedType)
573 .getFractionDigits());
574 } else if (referencedType instanceof IntegerTypeDefinition) {
575 constraints.addRanges(((IntegerTypeDefinition) referencedType)
576 .getRangeStatements());
577 } else if (referencedType instanceof StringTypeDefinition) {
578 constraints.addPatterns(((StringTypeDefinition) referencedType)
580 constraints.addLengths(((StringTypeDefinition) referencedType)
581 .getLengthStatements());
582 } else if (referencedType instanceof BinaryTypeDefinition) {
583 constraints.addLengths(((BinaryTypeDefinition) referencedType)
584 .getLengthConstraints());
589 * Go through all augmentation definitions and resolve them. This method
590 * also finds referenced node and add child nodes to it.
593 * all available modules
595 private void resolveAugments(
596 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
597 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
598 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
599 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
601 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
603 allModulesList.add(inner.getValue());
604 allModulesSet.add(inner.getValue());
608 for (int i = 0; i < allModulesList.size(); i++) {
609 final ModuleBuilder module = allModulesList.get(i);
610 // try to resolve augments in module
611 resolveAugment(modules, module);
612 // while all augments are not resolved
613 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
615 while (!(module.getAugmentsResolved() == module.getAddedAugments()
617 ModuleBuilder nextModule = null;
618 // try resolve other module augments
620 nextModule = allModulesIterator.next();
621 resolveAugment(modules, nextModule);
622 } catch (NoSuchElementException e) {
623 throw new YangParseException(
624 "Failed to resolve augments in module '"
625 + module.getName() + "'.", e);
627 // then try to resolve first module again
628 resolveAugment(modules, module);
636 * all available modules
640 private void resolveAugment(
641 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
642 final ModuleBuilder module) {
643 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
644 for (AugmentationSchemaBuilder augmentBuilder : module
645 .getAddedAugments()) {
646 final SchemaPath augmentTargetSchemaPath = augmentBuilder
648 final List<QName> path = augmentTargetSchemaPath.getPath();
651 final QName qname = path.get(i);
652 String prefix = qname.getPrefix();
653 if (prefix == null) {
654 prefix = module.getPrefix();
657 DataSchemaNodeBuilder currentParent = null;
658 final ModuleBuilder dependentModule = findDependentModule(
659 modules, module, prefix);
660 for (DataSchemaNodeBuilder child : dependentModule
662 final QName childQName = child.getQName();
663 if (childQName.getLocalName().equals(qname.getLocalName())) {
664 currentParent = child;
670 for (; i < path.size(); i++) {
671 final QName currentQName = path.get(i);
672 DataSchemaNodeBuilder newParent = null;
673 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
675 final QName childQName = child.getQName();
676 if (childQName.getLocalName().equals(
677 currentQName.getLocalName())) {
682 if (newParent == null) {
683 break; // node not found, quit search
685 currentParent = newParent;
689 final QName currentQName = currentParent.getQName();
690 final QName lastAugmentPathElement = path.get(path.size() - 1);
691 if (currentQName.getLocalName().equals(
692 lastAugmentPathElement.getLocalName())) {
693 ParserUtils.fillAugmentTarget(augmentBuilder,
694 (ChildNodeBuilder) currentParent);
695 ((AugmentationTargetBuilder) currentParent)
696 .addAugmentation(augmentBuilder);
697 module.augmentResolved();
704 * Go through identity statements defined in current module and resolve
705 * their 'base' statement if present.
710 * module being resolved
712 private void resolveIdentities(
713 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
714 final ModuleBuilder module) {
715 final Set<IdentitySchemaNodeBuilder> identities = module
716 .getAddedIdentities();
717 for (IdentitySchemaNodeBuilder identity : identities) {
718 final String baseIdentityName = identity.getBaseIdentityName();
719 if (baseIdentityName != null) {
720 String baseIdentityPrefix = null;
721 String baseIdentityLocalName = null;
722 if (baseIdentityName.contains(":")) {
723 final String[] splitted = baseIdentityName.split(":");
724 baseIdentityPrefix = splitted[0];
725 baseIdentityLocalName = splitted[1];
727 baseIdentityPrefix = module.getPrefix();
728 baseIdentityLocalName = baseIdentityName;
730 final ModuleBuilder dependentModule = findDependentModule(
731 modules, module, baseIdentityPrefix);
733 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
734 .getAddedIdentities();
735 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
736 if (idBuilder.getQName().getLocalName()
737 .equals(baseIdentityLocalName)) {
738 identity.setBaseIdentity(idBuilder);
746 * Go through uses statements defined in current module and resolve their
752 * module being resolved
754 private void resolveUses(
755 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
756 final ModuleBuilder module) {
757 final Map<List<String>, UsesNodeBuilder> moduleUses = module
758 .getAddedUsesNodes();
759 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
761 final List<String> key = entry.getKey();
762 final UsesNodeBuilder usesNode = entry.getValue();
764 final String groupingName = key.get(key.size() - 1);
766 for (RefineHolder refine : usesNode.getRefines()) {
768 final String defaultStr = refine.getDefaultStr();
769 final Boolean mandatory = refine.isMandatory();
770 final MustDefinition must = refine.getMust();
771 final Boolean presence = refine.isPresence();
772 final Integer min = refine.getMinElements();
773 final Integer max = refine.getMaxElements();
774 final List<UnknownSchemaNodeBuilder> unknownNodes = refine
777 Builder refineTarget = getRefineTargetBuilder(groupingName,
778 refine, modules, module);
779 if (refineTarget instanceof LeafSchemaNodeBuilder) {
780 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
781 if (defaultStr != null && !("".equals(defaultStr))) {
782 leaf.setDefaultStr(defaultStr);
784 if (mandatory != null) {
785 leaf.getConstraints().setMandatory(mandatory);
788 leaf.getConstraints().addMustDefinition(must);
790 if (unknownNodes != null) {
791 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
792 leaf.addUnknownSchemaNode(unknown);
795 usesNode.addRefineNode(leaf);
796 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
797 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
798 if (presence != null) {
799 container.setPresence(presence);
802 container.getConstraints().addMustDefinition(must);
804 if (unknownNodes != null) {
805 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
806 container.addUnknownSchemaNode(unknown);
809 usesNode.addRefineNode(container);
810 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
811 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
813 list.getConstraints().addMustDefinition(must);
816 list.getConstraints().setMinElements(min);
819 list.getConstraints().setMaxElements(max);
821 if (unknownNodes != null) {
822 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
823 list.addUnknownSchemaNode(unknown);
826 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
827 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
828 groupingName, refine, modules, module);
830 leafList.getConstraints().addMustDefinition(must);
833 leafList.getConstraints().setMinElements(min);
836 leafList.getConstraints().setMaxElements(max);
838 if (unknownNodes != null) {
839 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
840 leafList.addUnknownSchemaNode(unknown);
843 } else if (refineTarget instanceof ChoiceBuilder) {
844 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
845 if (defaultStr != null) {
846 choice.setDefaultCase(defaultStr);
848 if (mandatory != null) {
849 choice.getConstraints().setMandatory(mandatory);
851 if (unknownNodes != null) {
852 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
853 choice.addUnknownSchemaNode(unknown);
856 } else if (refineTarget instanceof AnyXmlBuilder) {
857 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
858 if (mandatory != null) {
859 anyXml.getConstraints().setMandatory(mandatory);
862 anyXml.getConstraints().addMustDefinition(must);
864 if (unknownNodes != null) {
865 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
866 anyXml.addUnknownSchemaNode(unknown);
875 * Find original builder of refine node and return copy of this builder.
877 * @param groupingPath
878 * path to grouping which contains node to refine
880 * refine object containing informations about refine
885 * @return copy of Builder object of node to be refined if it is present in
886 * grouping, null otherwise
888 private Builder getRefineTargetBuilder(final String groupingPath,
889 final RefineHolder refine,
890 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
891 final ModuleBuilder module) {
892 Builder result = null;
893 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
894 refine.getName(), modules, module);
895 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
897 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
898 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
900 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
901 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
903 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
904 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
906 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
907 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
909 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
910 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
912 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
914 throw new YangParseException("Target '" + refine.getName()
915 + "' can not be refined");
921 * Find builder of refine node.
923 * @param groupingPath
924 * path to grouping which contains node to refine
925 * @param refineNodeName
926 * name of node to be refined
931 * @return Builder object of refine node if it is present in grouping, null
934 private Builder findRefineTargetBuilder(final String groupingPath,
935 final String refineNodeName,
936 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
937 final ModuleBuilder module) {
938 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
939 final List<String> builderPath = new ArrayList<String>();
940 String prefix = null;
941 for (QName qname : path.getPath()) {
942 builderPath.add(qname.getLocalName());
943 prefix = qname.getPrefix();
945 if (prefix == null) {
946 prefix = module.getPrefix();
949 final ModuleBuilder dependentModule = findDependentModule(modules,
951 builderPath.add(0, "grouping");
952 builderPath.add(0, dependentModule.getName());
953 final GroupingBuilder builder = (GroupingBuilder) dependentModule
954 .getNode(builderPath);
956 return builder.getChildNode(refineNodeName);
959 private QName findFullQName(
960 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
961 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
963 String baseString = idref.getBaseString();
964 if (baseString.contains(":")) {
965 String[] splittedBase = baseString.split(":");
966 if (splittedBase.length > 2) {
967 throw new YangParseException(
968 "Failed to parse identityref base: " + baseString);
970 String prefix = splittedBase[0];
971 String name = splittedBase[1];
972 ModuleBuilder dependentModule = findDependentModule(modules,
974 result = new QName(dependentModule.getNamespace(),
975 dependentModule.getRevision(), prefix, name);
977 result = new QName(module.getNamespace(), module.getRevision(),
978 module.getPrefix(), baseString);
983 private void resolveUnknownNodes(
984 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
985 final ModuleBuilder module) {
986 for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
987 QName nodeType = usnb.getNodeType();
988 if (nodeType.getNamespace() == null
989 || nodeType.getRevision() == null) {
991 ModuleBuilder dependentModule = findDependentModule(
992 modules, module, nodeType.getPrefix());
993 QName newNodeType = new QName(
994 dependentModule.getNamespace(),
995 dependentModule.getRevision(),
996 nodeType.getPrefix(), nodeType.getLocalName());
997 usnb.setNodeType(newNodeType);
998 } catch (YangParseException e) {
999 logger.debug("Failed to find unknown node type: "
1007 * Find dependent module based on given prefix
1010 * all available modules
1014 * target module prefix
1017 private ModuleBuilder findDependentModule(
1018 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1019 final ModuleBuilder module, final String prefix) {
1020 ModuleBuilder dependentModule = null;
1021 Date dependentModuleRevision = null;
1023 if (prefix.equals(module.getPrefix())) {
1024 dependentModule = module;
1026 final ModuleImport dependentModuleImport = ParserUtils
1027 .getModuleImport(module, prefix);
1028 if (dependentModuleImport == null) {
1029 throw new YangParseException("No import found with prefix '"
1030 + prefix + "' in module " + module.getName() + "'.");
1032 final String dependentModuleName = dependentModuleImport
1034 dependentModuleRevision = dependentModuleImport.getRevision();
1036 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1037 .get(dependentModuleName);
1038 if (moduleBuildersByRevision == null) {
1039 throw new YangParseException(
1040 "Failed to find dependent module '"
1041 + dependentModuleName + "' needed by module '"
1042 + module.getName() + "'.");
1044 if (dependentModuleRevision == null) {
1045 dependentModule = moduleBuildersByRevision.lastEntry()
1048 dependentModule = moduleBuildersByRevision
1049 .get(dependentModuleRevision);
1053 if (dependentModule == null) {
1054 throw new YangParseException(
1055 "Failed to find dependent module with prefix '" + prefix
1056 + "' and revision '" + dependentModuleRevision
1059 return dependentModule;
1062 private static class SchemaContextImpl implements SchemaContext {
1063 private final Set<Module> modules;
1065 private SchemaContextImpl(final Set<Module> modules) {
1066 this.modules = modules;
1070 public Set<DataSchemaNode> getDataDefinitions() {
1071 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
1072 for (Module m : modules) {
1073 dataDefs.addAll(m.getChildNodes());
1079 public Set<Module> getModules() {
1084 public Set<NotificationDefinition> getNotifications() {
1085 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
1086 for (Module m : modules) {
1087 notifications.addAll(m.getNotifications());
1089 return notifications;
1093 public Set<RpcDefinition> getOperations() {
1094 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
1095 for (Module m : modules) {
1096 rpcs.addAll(m.getRpcs());
1102 public Set<ExtensionDefinition> getExtensions() {
1103 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
1104 for (Module m : modules) {
1105 extensions.addAll(m.getExtensionSchemaNodes());
1111 public Module findModuleByName(final String name, final Date revision) {
1112 if ((name != null) && (revision != null)) {
1113 for (final Module module : modules) {
1114 if (module.getName().equals(name)
1115 && module.getRevision().equals(revision)) {
1124 public Module findModuleByNamespace(final URI namespace) {
1125 if (namespace != null) {
1126 for (final Module module : modules) {
1127 if (module.getNamespace().equals(namespace)) {