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;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedHashMap;
22 import java.util.LinkedHashSet;
23 import java.util.List;
25 import java.util.NoSuchElementException;
27 import java.util.TreeMap;
29 import org.antlr.v4.runtime.ANTLRInputStream;
30 import org.antlr.v4.runtime.CommonTokenStream;
31 import org.antlr.v4.runtime.tree.ParseTree;
32 import org.antlr.v4.runtime.tree.ParseTreeWalker;
33 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
35 import org.opendaylight.controller.yang.common.QName;
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.SchemaContext;
39 import org.opendaylight.controller.yang.model.api.SchemaPath;
40 import org.opendaylight.controller.yang.model.api.TypeDefinition;
41 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
42 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
45 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
46 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
47 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
48 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
49 import org.opendaylight.controller.yang.model.util.ExtendedType;
50 import org.opendaylight.controller.yang.model.util.IdentityrefType;
51 import org.opendaylight.controller.yang.model.util.UnknownType;
52 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
53 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
54 import org.opendaylight.controller.yang.parser.builder.api.Builder;
55 import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
56 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
57 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
58 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
61 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
63 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
64 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
65 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
66 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
74 import org.opendaylight.controller.yang.parser.util.ParserUtils;
75 import org.opendaylight.controller.yang.parser.util.RefineHolder;
76 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
77 import org.opendaylight.controller.yang.parser.util.YangParseException;
78 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
82 public final class YangParserImpl implements YangModelParser {
84 private static final Logger logger = LoggerFactory
85 .getLogger(YangParserImpl.class);
88 public Set<Module> parseYangModels(final List<File> yangFiles) {
89 if (yangFiles != null) {
90 final List<InputStream> inputStreams = new ArrayList<InputStream>();
92 for (final File yangFile : yangFiles) {
94 inputStreams.add(new FileInputStream(yangFile));
95 } catch (FileNotFoundException e) {
96 logger.warn("Exception while reading yang file: "
97 + yangFile.getName(), e);
100 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
101 return build(modules);
103 return Collections.emptySet();
107 public Set<Module> parseYangModelsFromStreams(
108 final List<InputStream> yangModelStreams) {
109 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
110 return build(modules);
114 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
115 return new SchemaContextImpl(modules);
118 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
119 final List<InputStream> yangFileStreams) {
120 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
121 // of items stored in map.
122 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
123 final ParseTreeWalker walker = new ParseTreeWalker();
124 final List<ParseTree> trees = parseStreams(yangFileStreams);
125 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
128 new YangModelBasicValidator(walker).validate(trees);
130 YangParserListenerImpl yangModelParser = null;
131 for (int i = 0; i < trees.size(); i++) {
132 yangModelParser = new YangParserListenerImpl();
133 walker.walk(yangModelParser, trees.get(i));
134 builders[i] = yangModelParser.getModuleBuilder();
137 // module dependency graph sorted
138 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
140 for (ModuleBuilder builder : sorted) {
141 final String builderName = builder.getName();
142 Date builderRevision = builder.getRevision();
143 if (builderRevision == null) {
144 builderRevision = new Date(0L);
146 TreeMap<Date, ModuleBuilder> builderByRevision = modules
148 if (builderByRevision == null) {
149 builderByRevision = new TreeMap<Date, ModuleBuilder>();
151 builderByRevision.put(builderRevision, builder);
152 modules.put(builderName, builderByRevision);
157 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
158 final List<ParseTree> trees = new ArrayList<ParseTree>();
159 for (InputStream yangStream : yangStreams) {
160 trees.add(parseStream(yangStream));
165 private ParseTree parseStream(final InputStream yangStream) {
166 ParseTree result = null;
168 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
169 final YangLexer lexer = new YangLexer(input);
170 final CommonTokenStream tokens = new CommonTokenStream(lexer);
171 final YangParser parser = new YangParser(tokens);
172 result = parser.yang();
173 } catch (IOException e) {
174 logger.warn("Exception while reading yang file: " + yangStream, e);
179 private Set<Module> build(
180 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
181 // fix unresolved nodes
182 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
184 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
186 final ModuleBuilder moduleBuilder = childEntry.getValue();
187 fixUnresolvedNodes(modules, moduleBuilder);
190 resolveAugments(modules);
193 // Linked Hash Set MUST be used otherwise the Set will not maintain
195 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html
196 final Set<Module> result = new LinkedHashSet<Module>();
197 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
199 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
200 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
202 final ModuleBuilder moduleBuilder = childEntry.getValue();
203 final Module module = moduleBuilder.build();
204 modulesByRevision.put(childEntry.getKey(), module);
211 private void fixUnresolvedNodes(
212 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
213 final ModuleBuilder builder) {
214 resolveDirtyNodes(modules, builder);
215 resolveIdentities(modules, builder);
216 resolveUses(modules, builder);
217 resolveUnknownNodes(modules, builder);
221 * Search for dirty nodes (node which contains UnknownType) and resolve
225 * all available modules
229 private void resolveDirtyNodes(
230 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
231 final ModuleBuilder module) {
232 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
234 if (!dirtyNodes.isEmpty()) {
235 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
238 final TypeAwareBuilder nodeToResolve = entry.getValue();
239 // different handling for union types
240 if (nodeToResolve instanceof UnionTypeBuilder) {
241 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
242 final List<TypeDefinition<?>> unionTypes = union.getTypes();
243 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
244 for (TypeDefinition<?> td : unionTypes) {
245 if (td instanceof UnknownType) {
246 final UnknownType unknownType = (UnknownType) td;
247 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
248 nodeToResolve, unknownType, modules, module);
249 union.setType(resolvedType);
250 toRemove.add(unknownType);
253 unionTypes.removeAll(toRemove);
254 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
255 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
257 nodeToResolve.setType(new IdentityrefType(findFullQName(
258 modules, module, idref), idref.getPath()));
260 final TypeDefinitionBuilder resolvedType = resolveType(
261 nodeToResolve, modules, module);
262 nodeToResolve.setType(resolvedType);
268 private TypeDefinitionBuilder resolveType(
269 final TypeAwareBuilder typeToResolve,
270 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
271 final ModuleBuilder builder) {
272 final TypeConstraints constraints = new TypeConstraints();
274 final TypeDefinitionBuilder targetType = getTypedefBuilder(
275 typeToResolve, modules, builder);
276 final TypeConstraints tConstraints = findConstraints(typeToResolve,
277 constraints, modules, builder);
278 targetType.setRanges(tConstraints.getRange());
279 targetType.setLengths(tConstraints.getLength());
280 targetType.setPatterns(tConstraints.getPatterns());
281 targetType.setFractionDigits(tConstraints.getFractionDigits());
286 private TypeDefinitionBuilder resolveTypeUnion(
287 final TypeAwareBuilder typeToResolve,
288 final UnknownType unknownType,
289 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
290 final ModuleBuilder builder) {
291 final TypeConstraints constraints = new TypeConstraints();
293 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
294 unknownType, modules, builder);
295 final TypeConstraints tConstraints = findConstraints(typeToResolve,
296 constraints, modules, builder);
297 targetType.setRanges(tConstraints.getRange());
298 targetType.setLengths(tConstraints.getLength());
299 targetType.setPatterns(tConstraints.getPatterns());
300 targetType.setFractionDigits(tConstraints.getFractionDigits());
305 private TypeDefinitionBuilder getTypedefBuilder(
306 final TypeAwareBuilder nodeToResolve,
307 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
308 final ModuleBuilder builder) {
310 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
311 if (nodeToResolveBase != null
312 && !(nodeToResolveBase instanceof UnknownType)) {
313 return (TypeDefinitionBuilder) nodeToResolve;
316 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
317 final QName unknownTypeQName = unknownType.getQName();
319 // search for module which contains referenced typedef
320 final ModuleBuilder dependentModule = findDependentModule(modules,
321 builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
322 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
323 dependentModule, unknownTypeQName.getLocalName(),
324 builder.getName(), nodeToResolve.getLine());
326 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
327 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
328 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
329 lookedUpBuilderCopy, modules, dependentModule);
333 private TypeDefinitionBuilder getUnionBuilder(
334 final TypeAwareBuilder nodeToResolve,
335 final UnknownType unknownType,
336 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
337 final ModuleBuilder module) {
339 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
340 if (baseTypeToResolve != null
341 && !(baseTypeToResolve instanceof UnknownType)) {
342 return (TypeDefinitionBuilder) nodeToResolve;
345 final QName unknownTypeQName = unknownType.getQName();
346 // search for module which contains referenced typedef
347 final ModuleBuilder dependentModule = findDependentModule(modules,
348 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
349 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
350 dependentModule, unknownTypeQName.getLocalName(),
351 module.getName(), nodeToResolve.getLine());
353 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
354 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
355 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
356 lookedUpBuilderCopy, modules, dependentModule);
360 private TypeDefinitionBuilder copyTypedefBuilder(
361 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
362 if (old instanceof UnionTypeBuilder) {
363 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
364 final UnionTypeBuilder newUnion = new UnionTypeBuilder(old.getLine());
365 for (TypeDefinition<?> td : oldUnion.getTypes()) {
366 newUnion.setType(td);
368 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
369 newUnion.setType(copyTypedefBuilder(tdb, true));
371 newUnion.setPath(old.getPath());
375 final QName oldName = old.getQName();
376 final QName newName = new QName(oldName.getNamespace(),
377 oldName.getRevision(), oldName.getPrefix(),
378 oldName.getLocalName());
379 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName,
382 tdb.setRanges(old.getRanges());
383 tdb.setLengths(old.getLengths());
384 tdb.setPatterns(old.getPatterns());
385 tdb.setFractionDigits(old.getFractionDigits());
386 tdb.setPath(old.getPath());
388 final TypeDefinition<?> oldType = old.getType();
389 if (oldType == null) {
390 tdb.setType(old.getTypedef());
392 tdb.setType(oldType);
395 if (!seekByTypedefBuilder) {
396 tdb.setDescription(old.getDescription());
397 tdb.setReference(old.getReference());
398 tdb.setStatus(old.getStatus());
399 tdb.setDefaultValue(old.getDefaultValue());
400 tdb.setUnits(old.getUnits());
405 private TypeDefinitionBuilder resolveCopiedBuilder(
406 final TypeDefinitionBuilder copy,
407 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
408 final ModuleBuilder builder) {
410 if (copy instanceof UnionTypeBuilder) {
411 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
412 final List<TypeDefinition<?>> unionTypes = union.getTypes();
413 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
414 for (TypeDefinition<?> td : unionTypes) {
415 if (td instanceof UnknownType) {
416 final UnknownType unknownType = (UnknownType) td;
417 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
418 union, unknownType, modules, builder);
419 union.setType(resolvedType);
420 toRemove.add(unknownType);
423 unionTypes.removeAll(toRemove);
428 final TypeDefinition<?> base = copy.getType();
429 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
430 if (base != null && !(base instanceof UnknownType)) {
432 } else if (base instanceof UnknownType) {
433 final UnknownType unknownType = (UnknownType) base;
434 final QName unknownTypeQName = unknownType.getQName();
435 final String unknownTypePrefix = unknownTypeQName.getPrefix();
436 final ModuleBuilder dependentModule = findDependentModule(modules,
437 builder, unknownTypePrefix, copy.getLine());
438 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
439 modules, dependentModule);
440 copy.setType(utBuilder);
442 } else if (base == null && baseTdb != null) {
443 // make a copy of baseTypeDef and call again
444 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
446 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
447 baseTdbCopy, modules, builder);
448 copy.setType(baseTdbCopyResolved);
451 throw new IllegalStateException("Failed to resolve type "
452 + copy.getQName().getLocalName());
456 private TypeDefinitionBuilder findTypedefBuilder(
457 final QName unknownTypeQName,
458 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
459 final ModuleBuilder builder, int line) {
460 // search for module which contains referenced typedef
461 final ModuleBuilder dependentModule = findDependentModule(modules,
462 builder, unknownTypeQName.getPrefix(), line);
463 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
464 dependentModule, unknownTypeQName.getLocalName(),
465 builder.getName(), line);
466 return copyTypedefBuilder(lookedUpBuilder, true);
469 private TypeConstraints findConstraints(
470 final TypeAwareBuilder nodeToResolve,
471 final TypeConstraints constraints,
472 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
473 final ModuleBuilder builder) {
474 // union type cannot be restricted
475 if (nodeToResolve instanceof UnionTypeBuilder) {
479 // if referenced type is UnknownType again, search recursively with
480 // current constraints
481 final TypeDefinition<?> referencedType = nodeToResolve.getType();
482 List<RangeConstraint> ranges = Collections.emptyList();
483 List<LengthConstraint> lengths = Collections.emptyList();
484 List<PatternConstraint> patterns = Collections.emptyList();
485 Integer fractionDigits = null;
486 if (referencedType == null) {
487 final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef();
488 ranges = tdb.getRanges();
489 constraints.addRanges(ranges);
490 lengths = tdb.getLengths();
491 constraints.addLengths(lengths);
492 patterns = tdb.getPatterns();
493 constraints.addPatterns(patterns);
494 fractionDigits = tdb.getFractionDigits();
495 constraints.setFractionDigits(fractionDigits);
497 } else if (referencedType instanceof ExtendedType) {
498 final ExtendedType ext = (ExtendedType) referencedType;
499 ranges = ext.getRanges();
500 constraints.addRanges(ranges);
501 lengths = ext.getLengths();
502 constraints.addLengths(lengths);
503 patterns = ext.getPatterns();
504 constraints.addPatterns(patterns);
505 fractionDigits = ext.getFractionDigits();
506 constraints.setFractionDigits(fractionDigits);
507 return findConstraints(
508 findTypedefBuilder(ext.getQName(), modules, builder,
509 nodeToResolve.getLine()), constraints, modules,
511 } else if (referencedType instanceof UnknownType) {
512 final UnknownType unknown = (UnknownType) referencedType;
513 ranges = unknown.getRangeStatements();
514 constraints.addRanges(ranges);
515 lengths = unknown.getLengthStatements();
516 constraints.addLengths(lengths);
517 patterns = unknown.getPatterns();
518 constraints.addPatterns(patterns);
519 fractionDigits = unknown.getFractionDigits();
520 constraints.setFractionDigits(fractionDigits);
522 String unknownTypePrefix = unknown.getQName().getPrefix();
523 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
524 unknownTypePrefix = builder.getPrefix();
526 final ModuleBuilder dependentModule = findDependentModule(modules,
527 builder, unknown.getQName().getPrefix(),
528 nodeToResolve.getLine());
529 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
530 unknown.getQName(), modules, builder,
531 nodeToResolve.getLine());
532 return findConstraints(utBuilder, constraints, modules,
535 // HANDLE BASE YANG TYPE
536 mergeConstraints(referencedType, constraints);
542 * Search for type definition builder by name.
544 * @param dependentModule
547 * name of type definition
548 * @param currentModuleName
549 * current module name
551 * current line in yang model
554 private TypeDefinitionBuilder findTypedefBuilderByName(
555 final ModuleBuilder dependentModule, final String name,
556 final String currentModuleName, final int line) {
557 final Set<TypeDefinitionBuilder> typedefs = dependentModule
558 .getModuleTypedefs();
559 for (TypeDefinitionBuilder td : typedefs) {
560 if (td.getQName().getLocalName().equals(name)) {
564 throw new YangParseException(currentModuleName, line, "Target module '"
565 + dependentModule.getName() + "' does not contain typedef '"
570 * Pull restriction from referenced type and add them to given constraints
572 * @param referencedType
575 private void mergeConstraints(final TypeDefinition<?> referencedType,
576 final TypeConstraints constraints) {
578 if (referencedType instanceof DecimalTypeDefinition) {
579 constraints.addRanges(((DecimalTypeDefinition) referencedType)
580 .getRangeStatements());
582 .setFractionDigits(((DecimalTypeDefinition) referencedType)
583 .getFractionDigits());
584 } else if (referencedType instanceof IntegerTypeDefinition) {
585 constraints.addRanges(((IntegerTypeDefinition) referencedType)
586 .getRangeStatements());
587 } else if (referencedType instanceof StringTypeDefinition) {
588 constraints.addPatterns(((StringTypeDefinition) referencedType)
590 constraints.addLengths(((StringTypeDefinition) referencedType)
591 .getLengthStatements());
592 } else if (referencedType instanceof BinaryTypeDefinition) {
593 constraints.addLengths(((BinaryTypeDefinition) referencedType)
594 .getLengthConstraints());
599 * Go through all augment definitions and resolve them. This method also
600 * finds augment target node and add child nodes to it.
603 * all available modules
605 private void resolveAugments(
606 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
607 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
608 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
609 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
611 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
613 allModulesList.add(inner.getValue());
614 allModulesSet.add(inner.getValue());
618 for (int i = 0; i < allModulesList.size(); i++) {
619 final ModuleBuilder module = allModulesList.get(i);
620 // try to resolve augments in module
621 resolveAugment(modules, module);
622 // while all augments are not resolved
623 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
625 while (!(module.getAugmentsResolved() == module.getAddedAugments()
627 ModuleBuilder nextModule = null;
628 // try resolve other module augments
630 nextModule = allModulesIterator.next();
631 resolveAugment(modules, nextModule);
632 } catch (NoSuchElementException e) {
633 throw new YangParseException(
634 "Failed to resolve augments in module '"
635 + module.getName() + "'.", e);
637 // then try to resolve first module again
638 resolveAugment(modules, module);
646 * all available modules
650 private void resolveAugment(
651 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
652 final ModuleBuilder module) {
653 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
654 for (AugmentationSchemaBuilder augmentBuilder : module
655 .getAddedAugments()) {
657 if (!augmentBuilder.isResolved()) {
658 final SchemaPath augmentTargetSchemaPath = augmentBuilder
660 final List<QName> path = augmentTargetSchemaPath.getPath();
662 final QName qname = path.get(0);
663 String prefix = qname.getPrefix();
664 if (prefix == null) {
665 prefix = module.getPrefix();
668 DataSchemaNodeBuilder currentParent = null;
669 final ModuleBuilder dependentModule = findDependentModule(
670 modules, module, prefix, augmentBuilder.getLine());
671 for (DataSchemaNodeBuilder child : dependentModule
673 final QName childQName = child.getQName();
674 if (childQName.getLocalName().equals(
675 qname.getLocalName())) {
676 currentParent = child;
681 for (int i = 1; i < path.size(); i++) {
682 final QName currentQName = path.get(i);
683 DataSchemaNodeBuilder newParent = null;
684 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
686 final QName childQName = child.getQName();
687 if (childQName.getLocalName().equals(
688 currentQName.getLocalName())) {
693 if (newParent == null) {
694 break; // node not found, quit search
696 currentParent = newParent;
700 final QName currentQName = currentParent.getQName();
701 final QName lastAugmentPathElement = path
702 .get(path.size() - 1);
703 if (currentQName.getLocalName().equals(
704 lastAugmentPathElement.getLocalName())) {
705 ParserUtils.fillAugmentTarget(augmentBuilder,
706 (ChildNodeBuilder) currentParent);
707 ((AugmentationTargetBuilder) currentParent)
708 .addAugmentation(augmentBuilder);
709 SchemaPath oldPath = currentParent.getPath();
710 augmentBuilder.setTargetPath(new SchemaPath(oldPath
711 .getPath(), oldPath.isAbsolute()));
712 augmentBuilder.setResolved(true);
713 module.augmentResolved();
722 * Go through identity statements defined in current module and resolve
723 * their 'base' statement if present.
728 * module being resolved
730 private void resolveIdentities(
731 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
732 final ModuleBuilder module) {
733 final Set<IdentitySchemaNodeBuilder> identities = module
734 .getAddedIdentities();
735 for (IdentitySchemaNodeBuilder identity : identities) {
736 final String baseIdentityName = identity.getBaseIdentityName();
737 if (baseIdentityName != null) {
738 String baseIdentityPrefix = null;
739 String baseIdentityLocalName = null;
740 if (baseIdentityName.contains(":")) {
741 final String[] splitted = baseIdentityName.split(":");
742 baseIdentityPrefix = splitted[0];
743 baseIdentityLocalName = splitted[1];
745 baseIdentityPrefix = module.getPrefix();
746 baseIdentityLocalName = baseIdentityName;
748 final ModuleBuilder dependentModule = findDependentModule(
749 modules, module, baseIdentityPrefix, identity.getLine());
751 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
752 .getAddedIdentities();
753 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
754 if (idBuilder.getQName().getLocalName()
755 .equals(baseIdentityLocalName)) {
756 identity.setBaseIdentity(idBuilder);
764 * Go through uses statements defined in current module and resolve their
770 * module being resolved
772 private void resolveUses(
773 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
774 final ModuleBuilder module) {
775 final Map<List<String>, UsesNodeBuilder> moduleUses = module
776 .getAddedUsesNodes();
777 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
779 final List<String> key = entry.getKey();
780 final UsesNodeBuilder usesNode = entry.getValue();
781 final int line = usesNode.getLine();
783 final String groupingName = key.get(key.size() - 1);
785 for (RefineHolder refine : usesNode.getRefines()) {
786 Builder refineTarget = getRefineNodeBuilderCopy(groupingName,
787 refine, modules, module);
788 ParserUtils.refineDefault(refineTarget, refine, line);
789 if (refineTarget instanceof LeafSchemaNodeBuilder) {
790 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
791 ParserUtils.refineLeaf(leaf, refine, line);
792 usesNode.addRefineNode(leaf);
793 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
794 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
795 ParserUtils.refineContainer(container, refine, line);
796 usesNode.addRefineNode(container);
797 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
798 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
799 ParserUtils.refineList(list, refine, line);
800 usesNode.addRefineNode(list);
801 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
802 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) refineTarget;
803 ParserUtils.refineLeafList(leafList, refine, line);
804 usesNode.addRefineNode(leafList);
805 } else if (refineTarget instanceof ChoiceBuilder) {
806 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
807 ParserUtils.refineChoice(choice, refine, line);
808 usesNode.addRefineNode(choice);
809 } else if (refineTarget instanceof AnyXmlBuilder) {
810 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
811 ParserUtils.refineAnyxml(anyXml, refine, line);
812 usesNode.addRefineNode(anyXml);
813 } else if(refineTarget instanceof GroupingBuilder) {
814 usesNode.addRefineNode((GroupingBuilder)refineTarget);
815 } else if(refineTarget instanceof TypedefBuilder) {
816 usesNode.addRefineNode((TypedefBuilder)refineTarget);
823 * Find original builder of node to refine and return copy of this builder.
825 * We must make a copy of builder to preserve original builder, because this
826 * object will be refined (modified) and later added to
827 * {@link UsesNodeBuilder}.
830 * @param groupingPath
831 * path to grouping which contains node to refine
833 * refine object containing informations about refine
838 * @return copy of node to be refined if it is present in grouping, null
841 private Builder getRefineNodeBuilderCopy(final String groupingPath,
842 final RefineHolder refine,
843 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
844 final ModuleBuilder module) {
845 Builder result = null;
846 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
847 refine, modules, module);
848 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
850 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
851 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
853 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
854 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
856 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
857 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
859 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
860 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
862 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
863 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
865 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
866 } else if (lookedUpBuilder instanceof GroupingBuilder) {
868 .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder);
869 } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
871 .copyTypedefBuilder((TypedefBuilder) lookedUpBuilder);
873 throw new YangParseException(module.getName(), refine.getLine(),
874 "Target '" + refine.getName() + "' can not be refined");
880 * Find builder of refine node.
882 * @param groupingPath
883 * path to grouping which contains node to refine
885 * object containing refine information
890 * @return Builder object of refine node if it is present in grouping, null
893 private Builder findRefineTargetBuilder(final String groupingPath,
894 final RefineHolder refine,
895 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
896 final ModuleBuilder module) {
897 final String refineNodeName = refine.getName();
898 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
899 final List<String> builderPath = new ArrayList<String>();
900 String prefix = null;
901 for (QName qname : path.getPath()) {
902 builderPath.add(qname.getLocalName());
903 prefix = qname.getPrefix();
905 if (prefix == null) {
906 prefix = module.getPrefix();
909 final ModuleBuilder dependentModule = findDependentModule(modules,
910 module, prefix, refine.getLine());
911 builderPath.add(0, "grouping");
912 builderPath.add(0, dependentModule.getName());
913 final GroupingBuilder builder = (GroupingBuilder) dependentModule
914 .getNode(builderPath);
916 Builder result = builder.getChildNode(refineNodeName);
918 Set<GroupingBuilder> grps = builder.getGroupings();
919 for(GroupingBuilder gr : grps) {
920 if(gr.getQName().getLocalName().equals(refineNodeName)) {
927 Set<TypeDefinitionBuilder> typedefs = builder.getTypedefs();
928 for(TypeDefinitionBuilder typedef : typedefs) {
929 if(typedef.getQName().getLocalName().equals(refineNodeName)) {
938 private QName findFullQName(
939 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
940 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
942 String baseString = idref.getBaseString();
943 if (baseString.contains(":")) {
944 String[] splittedBase = baseString.split(":");
945 if (splittedBase.length > 2) {
946 throw new YangParseException(module.getName(), idref.getLine(),
947 "Failed to parse identityref base: " + baseString);
949 String prefix = splittedBase[0];
950 String name = splittedBase[1];
951 ModuleBuilder dependentModule = findDependentModule(modules,
952 module, prefix, idref.getLine());
953 result = new QName(dependentModule.getNamespace(),
954 dependentModule.getRevision(), prefix, name);
956 result = new QName(module.getNamespace(), module.getRevision(),
957 module.getPrefix(), baseString);
962 private void resolveUnknownNodes(
963 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
964 final ModuleBuilder module) {
965 for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
966 QName nodeType = usnb.getNodeType();
967 if (nodeType.getNamespace() == null
968 || nodeType.getRevision() == null) {
970 ModuleBuilder dependentModule = findDependentModule(
971 modules, module, nodeType.getPrefix(),
973 QName newNodeType = new QName(
974 dependentModule.getNamespace(),
975 dependentModule.getRevision(),
976 nodeType.getPrefix(), nodeType.getLocalName());
977 usnb.setNodeType(newNodeType);
978 } catch (YangParseException e) {
979 logger.debug(module.getName(), usnb.getLine(),
980 "Failed to find unknown node type: " + nodeType);
987 * Find dependent module based on given prefix
990 * all available modules
994 * target module prefix
997 private ModuleBuilder findDependentModule(
998 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
999 final ModuleBuilder module, final String prefix, final int line) {
1000 ModuleBuilder dependentModule = null;
1001 Date dependentModuleRevision = null;
1003 if (prefix.equals(module.getPrefix())) {
1004 dependentModule = module;
1006 final ModuleImport dependentModuleImport = ParserUtils
1007 .getModuleImport(module, prefix);
1008 if (dependentModuleImport == null) {
1009 throw new YangParseException(module.getName(), line,
1010 "No import found with prefix '" + prefix + "'.");
1012 final String dependentModuleName = dependentModuleImport
1014 dependentModuleRevision = dependentModuleImport.getRevision();
1016 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1017 .get(dependentModuleName);
1018 if (moduleBuildersByRevision == null) {
1019 throw new YangParseException(module.getName(), line,
1020 "Failed to find dependent module '"
1021 + dependentModuleName + "'.");
1023 if (dependentModuleRevision == null) {
1024 dependentModule = moduleBuildersByRevision.lastEntry()
1027 dependentModule = moduleBuildersByRevision
1028 .get(dependentModuleRevision);
1032 if (dependentModule == null) {
1033 throw new YangParseException(module.getName(), line,
1034 "Failed to find dependent module with prefix '" + prefix
1035 + "' and revision '" + dependentModuleRevision
1038 return dependentModule;