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.yangtools.yang.parser.impl;
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveType;
12 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnion;
13 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeUnionWithContext;
14 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.resolveTypeWithContext;
17 import java.io.FileInputStream;
18 import java.io.FileNotFoundException;
19 import java.io.IOException;
20 import java.io.InputStream;
23 import java.util.Map.Entry;
25 import org.antlr.v4.runtime.ANTLRInputStream;
26 import org.antlr.v4.runtime.CommonTokenStream;
27 import org.antlr.v4.runtime.tree.ParseTree;
28 import org.antlr.v4.runtime.tree.ParseTreeWalker;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.model.api.*;
33 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
34 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
40 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.util.GroupingSort;
53 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
54 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
55 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
56 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
57 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 import com.google.common.base.Preconditions;
62 import com.google.common.collect.Lists;
63 import com.google.common.collect.Maps;
64 import com.google.common.collect.Sets;
66 public final class YangParserImpl implements YangModelParser {
67 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
69 private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
72 public Set<Module> parseYangModels(final File yangFile, final File directory) {
73 Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
74 Preconditions.checkState(directory.exists(), directory + " does not exists");
75 Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
77 final String yangFileName = yangFile.getName();
78 final String[] fileList = directory.list();
79 Preconditions.checkNotNull(fileList, directory + " not found");
81 FileInputStream yangFileStream = null;
82 LinkedHashMap<InputStream, File> streamToFileMap = new LinkedHashMap<>();
85 yangFileStream = new FileInputStream(yangFile);
86 streamToFileMap.put(yangFileStream, yangFile);
87 } catch (FileNotFoundException e) {
88 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
91 for (String fileName : fileList) {
92 if (fileName.equals(yangFileName)) {
95 File dependency = new File(directory, fileName);
97 if (dependency.isFile()) {
98 streamToFileMap.put(new FileInputStream(dependency), dependency);
100 } catch (FileNotFoundException e) {
101 LOG.warn("Exception while reading yang file: " + fileName, e);
105 Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()),
106 new HashMap<ModuleBuilder, InputStream>());
107 ModuleBuilder main = parsedBuilders.get(yangFileStream);
109 List<ModuleBuilder> moduleBuilders = new ArrayList<>();
110 moduleBuilders.add(main);
111 filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
113 ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()];
114 moduleBuilders.toArray(builders);
116 // module dependency graph sorted
117 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
119 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
120 return new LinkedHashSet<>(build(modules).values());
124 public Set<Module> parseYangModels(final List<File> yangFiles) {
125 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
129 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
130 if (yangFiles != null) {
131 final Map<InputStream, File> inputStreams = Maps.newHashMap();
133 for (final File yangFile : yangFiles) {
135 inputStreams.put(new FileInputStream(yangFile), yangFile);
136 } catch (FileNotFoundException e) {
137 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
141 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
142 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
143 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
145 for (InputStream is : inputStreams.keySet()) {
148 } catch (IOException e) {
149 LOG.debug("Failed to close stream.");
153 Collection<Module> built = buildWithContext(modules, context).values();
154 for (Module m : context.getModules()) {
155 if (!built.contains(m)) {
159 return new LinkedHashSet<>(built);
161 return Collections.emptySet();
165 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
166 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
170 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
171 if (yangModelStreams != null) {
172 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
173 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
174 yangModelStreams, builderToStreamMap, context);
176 final Set<Module> built = new LinkedHashSet<>(buildWithContext(modules, context).values());
177 for (Module m : context.getModules()) {
178 if (!built.contains(m)) {
184 return Collections.emptySet();
188 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
189 if (yangFiles != null) {
190 final Map<InputStream, File> inputStreams = Maps.newHashMap();
192 for (final File yangFile : yangFiles) {
194 inputStreams.put(new FileInputStream(yangFile), yangFile);
195 } catch (FileNotFoundException e) {
196 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
200 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
201 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
202 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
204 for (InputStream is : inputStreams.keySet()) {
207 } catch (IOException e) {
208 LOG.debug("Failed to close stream.");
212 Map<File, Module> retVal = Maps.newLinkedHashMap();
213 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
215 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
216 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
217 builderToModule.getValue());
222 return Collections.emptyMap();
226 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
227 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
229 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
231 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
232 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
234 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
235 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
241 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
242 return new SchemaContextImpl(modules);
245 private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
246 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
248 final ParseTreeWalker walker = new ParseTreeWalker();
249 final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
250 final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
253 new YangModelBasicValidator(walker).validate(new ArrayList<>(trees.values()));
255 YangParserListenerImpl yangModelParser;
256 for (Map.Entry<InputStream, ParseTree> entry : trees.entrySet()) {
257 yangModelParser = new YangParserListenerImpl();
258 walker.walk(yangModelParser, entry.getValue());
259 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
261 // We expect the order of trees and streams has to be the same
262 streamToBuilderMap.put(moduleBuilder, entry.getKey());
263 builders.put(entry.getKey(), moduleBuilder);
269 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
270 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
271 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
274 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
275 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
276 final SchemaContext context) {
277 Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
278 ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()];
279 parsedBuilders.values().toArray(builders);
281 // module dependency graph sorted
282 List<ModuleBuilder> sorted;
283 if (context == null) {
284 sorted = ModuleDependencySort.sort(builders);
286 sorted = ModuleDependencySort.sortWithContext(context, builders);
289 return orderModules(sorted);
293 * Order modules by name and revision.
297 * @return modules ordered by name and revision
299 private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(List<ModuleBuilder> modules) {
300 // LinkedHashMap must be used to preserve order
301 LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
302 for (final ModuleBuilder builder : modules) {
303 if (builder == null) {
306 final String builderName = builder.getName();
307 Date builderRevision = builder.getRevision();
308 if (builderRevision == null) {
309 builderRevision = new Date(0L);
311 TreeMap<Date, ModuleBuilder> builderByRevision = result.get(builderName);
312 if (builderByRevision == null) {
313 builderByRevision = new TreeMap<>();
315 builderByRevision.put(builderRevision, builder);
316 result.put(builderName, builderByRevision);
321 private void filterImports(ModuleBuilder main, List<ModuleBuilder> other, List<ModuleBuilder> filtered) {
322 for (ModuleImport mi : main.getModuleImports()) {
323 for (ModuleBuilder builder : other) {
324 if (mi.getModuleName().equals(builder.getModuleName())) {
325 if (mi.getRevision() == null) {
326 if (!filtered.contains(builder)) {
327 filtered.add(builder);
328 filterImports(builder, other, filtered);
331 if (mi.getRevision().equals(builder.getRevision())) {
332 if (!filtered.contains(builder)) {
333 filtered.add(builder);
334 filterImports(builder, other, filtered);
343 private Map<InputStream, ParseTree> parseStreams(final List<InputStream> yangStreams) {
344 final Map<InputStream, ParseTree> trees = new HashMap<>();
345 for (InputStream yangStream : yangStreams) {
346 trees.put(yangStream, parseStream(yangStream));
351 private ParseTree parseStream(final InputStream yangStream) {
352 ParseTree result = null;
354 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
355 final YangLexer lexer = new YangLexer(input);
356 final CommonTokenStream tokens = new CommonTokenStream(lexer);
357 final YangParser parser = new YangParser(tokens);
358 parser.removeErrorListeners();
359 YangErrorListener errorListener = new YangErrorListener();
360 parser.addErrorListener(errorListener);
361 result = parser.yang();
362 errorListener.validate();
363 } catch (IOException e) {
364 LOG.warn("Exception while reading yang file: " + yangStream, e);
369 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
370 // fix unresolved nodes
371 resolveDirtyNodes(modules);
372 resolveAugmentsTargetPath(modules, null);
373 resolveUsesTargetGrouping(modules, null);
374 resolveUsesForGroupings(modules, null);
375 resolveUsesForNodes(modules, null);
376 resolveAugments(modules, null);
377 resolveDeviations(modules);
380 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
381 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
382 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
383 final ModuleBuilder moduleBuilder = childEntry.getValue();
384 final Module module = moduleBuilder.build();
385 result.put(moduleBuilder, module);
391 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
392 final SchemaContext context) {
393 // fix unresolved nodes
394 resolvedDirtyNodesWithContext(modules, context);
395 resolveAugmentsTargetPath(modules, context);
396 resolveUsesTargetGrouping(modules, context);
397 resolveUsesForGroupings(modules, context);
398 resolveUsesForNodes(modules, context);
399 resolveAugments(modules, context);
400 resolveDeviationsWithContext(modules, context);
403 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
404 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
405 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
406 final ModuleBuilder moduleBuilder = childEntry.getValue();
407 final Module module = moduleBuilder.build();
408 result.put(moduleBuilder, module);
414 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
415 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
416 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
417 final ModuleBuilder module = childEntry.getValue();
418 resolveUnknownNodes(modules, module);
419 resolveIdentities(modules, module);
420 resolveDirtyNodes(modules, module);
425 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
426 final SchemaContext context) {
427 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
428 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
429 final ModuleBuilder module = childEntry.getValue();
430 resolveUnknownNodesWithContext(modules, module, context);
431 resolveIdentitiesWithContext(modules, module, context);
432 resolveDirtyNodesWithContext(modules, module, context);
438 * Search for dirty nodes (node which contains UnknownType) and resolve
442 * all available modules
446 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
447 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
448 if (!dirtyNodes.isEmpty()) {
449 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
450 if (nodeToResolve instanceof UnionTypeBuilder) {
451 // special handling for union types
452 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
453 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
454 // special handling for identityref types
455 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
456 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
458 if (identity == null) {
459 throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
461 idref.setBaseIdentity(identity);
462 nodeToResolve.setType(idref.build());
464 resolveType(nodeToResolve, modules, module);
470 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
471 final ModuleBuilder module, SchemaContext context) {
472 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
473 if (!dirtyNodes.isEmpty()) {
474 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
475 if (nodeToResolve instanceof UnionTypeBuilder) {
476 // special handling for union types
477 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
478 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
479 // special handling for identityref types
480 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
481 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
483 idref.setBaseIdentity(identity);
484 nodeToResolve.setType(idref.build());
486 resolveTypeWithContext(nodeToResolve, modules, module, context);
493 * Correct augment target path.
498 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
499 SchemaContext context) {
500 // collect augments from all loaded modules
501 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
502 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
503 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
504 allAugments.addAll(inner.getValue().getAllAugments());
508 for (AugmentationSchemaBuilder augment : allAugments) {
509 setCorrectAugmentTargetPath(modules, augment, context);
513 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
514 final AugmentationSchemaBuilder augment, final SchemaContext context) {
515 ModuleBuilder module = ParserUtils.getParentModule(augment);
516 SchemaPath oldSchemaPath = augment.getTargetPath();
517 List<QName> oldPath = oldSchemaPath.getPath();
518 List<QName> newPath = new ArrayList<>();
520 Builder parent = augment.getParent();
521 if (parent instanceof UsesNodeBuilder) {
522 DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
523 newPath.addAll(usesParent.getPath().getPath());
528 QName baseQName = usesParent.getQName();
529 if (baseQName == null) {
530 ModuleBuilder m = ParserUtils.getParentModule(usesParent);
531 ns = m.getNamespace();
532 revision = m.getRevision();
533 prefix = m.getPrefix();
535 ns = baseQName.getNamespace();
536 revision = baseQName.getRevision();
537 prefix = baseQName.getPrefix();
540 for (QName qn : oldSchemaPath.getPath()) {
541 newPath.add(new QName(ns, revision, prefix, qn.getLocalName()));
545 for (QName qn : oldPath) {
546 URI ns = module.getNamespace();
547 Date rev = module.getRevision();
548 String pref = module.getPrefix();
549 String localPrefix = qn.getPrefix();
550 if (localPrefix != null && !("".equals(localPrefix))) {
551 ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
553 if (currentModule == null) {
554 Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
556 throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
557 + localPrefix + " not found.");
559 ns = m.getNamespace();
560 rev = m.getRevision();
561 pref = m.getPrefix();
563 ns = currentModule.getNamespace();
564 rev = currentModule.getRevision();
565 pref = currentModule.getPrefix();
568 newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
571 augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
573 for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
574 correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
578 private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) {
579 SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName());
580 node.setPath(newPath);
581 if (node instanceof DataNodeContainerBuilder) {
582 for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodes()) {
583 correctPathForAugmentNodes(child, node.getPath());
586 if (node instanceof ChoiceBuilder) {
587 for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) {
588 correctPathForAugmentNodes(child, node.getPath());
594 * Check augments for mandatory nodes. If the target node is in another
595 * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
596 * If mandatory node is found, throw an exception.
601 private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
602 for (AugmentationSchemaBuilder augment : augments) {
603 String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
604 ModuleBuilder module = ParserUtils.getParentModule(augment);
605 String modulePrefix = module.getPrefix();
607 if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
611 for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
612 if (childNode.getConstraints().isMandatory()) {
613 throw new YangParseException(augment.getModuleName(), augment.getLine(),
614 "Error in augment parsing: cannot augment mandatory node "
615 + childNode.getQName().getLocalName());
622 * Go through all augment definitions and resolve them. This method works in
623 * same way as {@link #resolveAugments(Map)} except that if target node is
624 * not found in loaded modules, it search for target node in given context.
629 * SchemaContext containing already resolved modules
631 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
632 List<ModuleBuilder> all = new ArrayList<>();
633 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
634 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
635 all.add(inner.getValue());
639 List<ModuleBuilder> sorted;
640 if (context == null) {
641 sorted = ModuleDependencySort.sort(all.toArray(new ModuleBuilder[all.size()]));
643 sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()]));
646 // resolve other augments
647 for (ModuleBuilder mb : sorted) {
649 List<AugmentationSchemaBuilder> augments = mb.getAllAugments();
650 checkAugmentMandatoryNodes(augments);
651 for (AugmentationSchemaBuilder augment : augments) {
652 if (!(augment.isResolved())) {
653 boolean resolved = resolveAugment(augment, mb, modules, context);
655 throw new YangParseException(augment.getModuleName(), augment.getLine(),
656 "Error in augment parsing: failed to find augment target: " + augment);
665 private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
666 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
667 if (augment.isResolved()) {
671 UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent();
672 DataNodeContainerBuilder parentNode = usesNode.getParent();
673 SchemaNodeBuilder targetNode;
674 if (parentNode instanceof ModuleBuilder) {
675 targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder)parentNode);
677 targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder)parentNode);
680 fillAugmentTarget(augment, targetNode);
681 augment.setResolved(true);
685 private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
686 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
687 if (augment.isResolved()) {
691 List<QName> targetPath = augment.getTargetPath().getPath();
692 ModuleBuilder targetModule = findTargetModule(targetPath.get(0), module, modules, context, augment.getLine());
693 if (targetModule == null) {
694 throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment "
698 return processAugmentation(augment, targetModule);
702 * Find module from loaded modules or from context based on given qname. If
703 * module is found in context, create wrapper over this module and add it to
704 * collection of loaded modules.
717 private ModuleBuilder findTargetModule(final QName qname, final ModuleBuilder module,
718 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context, final int line) {
719 ModuleBuilder targetModule = null;
721 String prefix = qname.getPrefix();
722 if (prefix == null || prefix.equals("")) {
723 targetModule = module;
725 targetModule = findModuleFromBuilders(modules, module, qname.getPrefix(), line);
728 if (targetModule == null && context != null) {
729 Module m = findModuleFromContext(context, module, prefix, line);
730 targetModule = new ModuleBuilder(m);
731 DataSchemaNode firstNode = m.getDataChildByName(qname.getLocalName());
732 DataSchemaNodeBuilder firstNodeWrapped = wrapChildNode(targetModule.getModuleName(), line, firstNode,
733 targetModule.getPath(), firstNode.getQName());
734 targetModule.addChildNode(firstNodeWrapped);
736 TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
737 map.put(targetModule.getRevision(), targetModule);
738 modules.put(targetModule.getModuleName(), map);
745 * Go through identity statements defined in current module and resolve
746 * their 'base' statement if present.
751 * module being resolved
753 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
754 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
755 for (IdentitySchemaNodeBuilder identity : identities) {
756 final String baseIdentityName = identity.getBaseIdentityName();
757 final int line = identity.getLine();
758 if (baseIdentityName != null) {
759 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
760 if (baseIdentity == null) {
761 throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity");
763 identity.setBaseIdentity(baseIdentity);
770 * Go through identity statements defined in current module and resolve
771 * their 'base' statement. Method tries to find base identity in given
772 * modules. If base identity is not found, method will search it in context.
779 * SchemaContext containing already resolved modules
781 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
782 final ModuleBuilder module, final SchemaContext context) {
783 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
784 for (IdentitySchemaNodeBuilder identity : identities) {
785 final String baseIdentityName = identity.getBaseIdentityName();
786 final int line = identity.getLine();
787 if (baseIdentityName != null) {
788 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
789 if (baseIdentity == null) {
790 IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
792 identity.setBaseIdentity(baseId);
794 identity.setBaseIdentity(baseIdentity);
801 * Find and add reference of uses target grouping.
806 * SchemaContext containing already resolved modules or null if
807 * context is not available
809 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
810 final SchemaContext context) {
811 final List<UsesNodeBuilder> allUses = new ArrayList<>();
812 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
813 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
814 allUses.addAll(inner.getValue().getAllUsesNodes());
817 for (UsesNodeBuilder usesNode : allUses) {
818 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
819 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
821 if (targetGroupingBuilder == null) {
822 if (context == null) {
823 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
824 + usesNode.getGroupingPathAsString() + "' not found.");
826 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
828 usesNode.setGroupingDefinition(targetGroupingDefinition);
831 usesNode.setGrouping(targetGroupingBuilder);
836 private void resolveUsesForGroupings(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
837 final Set<GroupingBuilder> allGroupings = new HashSet<>();
838 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
839 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
840 ModuleBuilder module = inner.getValue();
841 allGroupings.addAll(module.getAllGroupings());
844 final List<GroupingBuilder> sorted = GroupingSort.sort(allGroupings);
845 for (GroupingBuilder gb : sorted) {
846 List<UsesNodeBuilder> usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb));
847 Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
848 for (UsesNodeBuilder usesNode : usesNodes) {
849 resolveUses(usesNode, modules, context);
854 private void resolveUsesForNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
855 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
856 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
857 ModuleBuilder module = inner.getValue();
858 List<UsesNodeBuilder> usesNodes = module.getAllUsesNodes();
859 Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
860 for (UsesNodeBuilder usesNode : usesNodes) {
861 resolveUses(usesNode, modules, context);
867 private void resolveUses(UsesNodeBuilder usesNode,
868 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
869 if (!usesNode.isResolved()) {
870 DataNodeContainerBuilder parent = usesNode.getParent();
871 ModuleBuilder module = ParserUtils.getParentModule(parent);
872 GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module);
873 if (target == null) {
874 resolveUsesWithContext(usesNode);
875 usesNode.setResolved(true);
876 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
877 resolveUsesAugment(augment, module, modules, context);
880 parent.getChildNodes().addAll(target.instantiateChildNodes(parent));
881 parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
882 parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
883 parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
884 usesNode.setResolved(true);
885 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
886 resolveUsesAugment(augment, module, modules, context);
889 GroupingUtils.performRefine(usesNode);
893 private void resolveUsesWithContext(UsesNodeBuilder usesNode) {
894 final int line = usesNode.getLine();
895 DataNodeContainerBuilder parent = usesNode.getParent();
896 ModuleBuilder module = ParserUtils.getParentModule(parent);
897 SchemaPath parentPath;
901 if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) {
902 ns = module.getNamespace();
903 rev = module.getRevision();
904 pref = module.getPrefix();
905 if (parent instanceof AugmentationSchemaBuilder) {
906 parentPath = ((AugmentationSchemaBuilder)parent).getTargetNodeSchemaPath();
908 parentPath = ((ModuleBuilder)parent).getPath();
911 ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace();
912 rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision();
913 pref = ((DataSchemaNodeBuilder) parent).getQName().getPrefix();
914 parentPath = ((DataSchemaNodeBuilder)parent).getPath();
917 GroupingDefinition gd = usesNode.getGroupingDefinition();
919 Set<DataSchemaNodeBuilder> childNodes = wrapChildNodes(module.getModuleName(), line,
920 gd.getChildNodes(), parentPath, ns, rev, pref);
921 parent.getChildNodes().addAll(childNodes);
922 for (DataSchemaNodeBuilder childNode : childNodes) {
923 setNodeAddedByUses(childNode);
926 Set<TypeDefinitionBuilder> typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, ns,
928 parent.getTypeDefinitionBuilders().addAll(typedefs);
929 for (TypeDefinitionBuilder typedef : typedefs) {
930 setNodeAddedByUses(typedef);
933 Set<GroupingBuilder> groupings = wrapGroupings(module.getModuleName(), line, usesNode
934 .getGroupingDefinition().getGroupings(), parentPath, ns, rev, pref);
935 parent.getGroupingBuilders().addAll(groupings);
936 for (GroupingBuilder gb : groupings) {
937 setNodeAddedByUses(gb);
940 List<UnknownSchemaNodeBuilder> unknownNodes = wrapUnknownNodes(module.getModuleName(), line,
941 gd.getUnknownSchemaNodes(), parentPath, ns, rev, pref);
942 parent.getUnknownNodes().addAll(unknownNodes);
943 for (UnknownSchemaNodeBuilder un : unknownNodes) {
944 un.setAddedByUses(true);
948 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
949 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
950 QName nodeType = usnb.getNodeType();
952 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
954 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
955 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
956 usnb.setNodeType(extension.getQName());
957 usnb.setExtensionBuilder(extension);
961 } catch (YangParseException e) {
962 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
963 + ": no such extension definition found.", e);
968 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
969 final ModuleBuilder module, final SchemaContext context) {
970 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
971 QName nodeType = usnb.getNodeType();
973 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
976 if (dependentModuleBuilder == null) {
977 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
979 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
980 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
981 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
982 nodeType.getPrefix(), e.getQName().getLocalName()));
983 usnb.setExtensionDefinition(e);
988 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
989 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
990 usnb.setExtensionBuilder(extension);
996 } catch (YangParseException e) {
997 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
998 + ": no such extension definition found.", e);
1005 * Traverse through modules and resolve their deviation statements.
1008 * all loaded modules
1010 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
1011 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1012 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1013 ModuleBuilder b = inner.getValue();
1014 resolveDeviation(modules, b);
1020 * Traverse through module and resolve its deviation statements.
1023 * all loaded modules
1025 * module in which resolve deviations
1027 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1028 for (DeviationBuilder dev : module.getDeviations()) {
1029 int line = dev.getLine();
1030 SchemaPath targetPath = dev.getTargetPath();
1031 List<QName> path = targetPath.getPath();
1032 QName q0 = path.get(0);
1033 String prefix = q0.getPrefix();
1034 if (prefix == null) {
1035 prefix = module.getPrefix();
1038 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1039 processDeviation(dev, dependentModuleBuilder, path, module);
1044 * Traverse through modules and resolve their deviation statements with
1048 * all loaded modules
1050 * already resolved context
1052 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1053 final SchemaContext context) {
1054 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1055 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1056 ModuleBuilder b = inner.getValue();
1057 resolveDeviationWithContext(modules, b, context);
1063 * Traverse through module and resolve its deviation statements with given
1067 * all loaded modules
1069 * module in which resolve deviations
1071 * already resolved context
1073 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1074 final ModuleBuilder module, final SchemaContext context) {
1075 for (DeviationBuilder dev : module.getDeviations()) {
1076 int line = dev.getLine();
1077 SchemaPath targetPath = dev.getTargetPath();
1078 List<QName> path = targetPath.getPath();
1079 QName q0 = path.get(0);
1080 String prefix = q0.getPrefix();
1081 if (prefix == null) {
1082 prefix = module.getPrefix();
1085 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1086 if (dependentModuleBuilder == null) {
1087 Object currentParent = findModuleFromContext(context, module, prefix, line);
1089 for (QName q : path) {
1090 if (currentParent == null) {
1091 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1093 String name = q.getLocalName();
1094 if (currentParent instanceof DataNodeContainer) {
1095 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1099 if (currentParent == null) {
1100 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1102 if (currentParent instanceof SchemaNode) {
1103 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1107 processDeviation(dev, dependentModuleBuilder, path, module);
1113 * Correct deviation target path in deviation builder.
1117 * @param dependentModuleBuilder
1118 * module containing deviation target
1120 * current deviation target path
1124 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1125 final List<QName> path, final ModuleBuilder module) {
1126 final int line = dev.getLine();
1127 Builder currentParent = dependentModuleBuilder;
1129 for (QName q : path) {
1130 if (currentParent == null) {
1131 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1133 String name = q.getLocalName();
1134 if (currentParent instanceof DataNodeContainerBuilder) {
1135 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1139 if (!(currentParent instanceof SchemaNodeBuilder)) {
1140 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1142 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());