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;
24 import org.antlr.v4.runtime.ANTLRInputStream;
25 import org.antlr.v4.runtime.CommonTokenStream;
26 import org.antlr.v4.runtime.tree.ParseTree;
27 import org.antlr.v4.runtime.tree.ParseTreeWalker;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.model.api.*;
32 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
33 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
37 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
38 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
39 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
40 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
41 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
42 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
43 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
44 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
46 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
51 import org.opendaylight.yangtools.yang.parser.util.GroupingSort;
52 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
53 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
54 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
55 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
56 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 import com.google.common.base.Preconditions;
63 public final class YangParserImpl implements YangModelParser {
64 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
66 private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
69 public Set<Module> parseYangModels(final File yangFile, final File directory) {
70 Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
71 Preconditions.checkState(directory.exists(), directory + " does not exists");
72 Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
74 final String yangFileName = yangFile.getName();
75 final String[] fileList = directory.list();
76 Preconditions.checkNotNull(fileList, directory + " not found");
78 FileInputStream yangFileStream = null;
79 LinkedHashMap<InputStream, File> streamToFileMap = new LinkedHashMap<>();
81 yangFileStream = new FileInputStream(yangFile);
82 streamToFileMap.put(yangFileStream, yangFile);
83 } catch (FileNotFoundException e) {
84 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
87 for (String fileName : fileList) {
88 if (fileName.equals(yangFileName)) {
91 File dependency = new File(directory, fileName);
93 if (dependency.isFile()) {
94 streamToFileMap.put(new FileInputStream(dependency), dependency);
96 } catch (FileNotFoundException e) {
97 LOG.warn("Exception while reading yang file: " + fileName, e);
101 Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(new ArrayList<>(streamToFileMap.keySet()),
102 new HashMap<ModuleBuilder, InputStream>());
103 ModuleBuilder main = parsedBuilders.get(yangFileStream);
105 List<ModuleBuilder> moduleBuilders = new ArrayList<>();
106 moduleBuilders.add(main);
107 filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
109 // module builders sorted by dependencies
110 ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()];
111 moduleBuilders.toArray(builders);
112 List<ModuleBuilder> sortedBuilders = ModuleDependencySort.sort(builders);
113 LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sortedBuilders);
114 Collection<Module> unsorted = build(modules).values();
115 return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
119 public Set<Module> parseYangModels(final List<File> yangFiles) {
120 Collection<Module> unsorted = parseYangModelsMapped(yangFiles).values();
121 return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
125 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
126 if (yangFiles == null) {
127 return Collections.emptySet();
130 final Map<InputStream, File> inputStreams = new HashMap<>();
131 for (final File yangFile : yangFiles) {
133 inputStreams.put(new FileInputStream(yangFile), yangFile);
134 } catch (FileNotFoundException e) {
135 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
139 List<InputStream> yangModelStreams = new ArrayList<>(inputStreams.keySet());
140 Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
141 Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
142 builderToStreamMap, null);
144 for (InputStream is : inputStreams.keySet()) {
147 } catch (IOException e) {
148 LOG.debug("Failed to close stream.");
152 final Collection<Module> unsorted = buildWithContext(modules, context).values();
153 if (context != null) {
154 for (Module m : context.getModules()) {
155 if (!unsorted.contains(m)) {
160 return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
164 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
165 Collection<Module> unsorted = parseYangModelsFromStreamsMapped(yangModelStreams).values();
166 return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
170 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
171 if (yangModelStreams == null) {
172 return Collections.emptySet();
175 final Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
176 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
177 builderToStreamMap, context);
178 final Set<Module> unsorted = new LinkedHashSet<>(buildWithContext(modules, context).values());
179 if (context != null) {
180 for (Module m : context.getModules()) {
181 if (!unsorted.contains(m)) {
186 return new LinkedHashSet<>(ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
190 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
191 if (yangFiles == null) {
192 return Collections.emptyMap();
195 final Map<InputStream, File> inputStreams = new HashMap<>();
196 for (final File yangFile : yangFiles) {
198 inputStreams.put(new FileInputStream(yangFile), yangFile);
199 } catch (FileNotFoundException e) {
200 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
204 List<InputStream> yangModelStreams = new ArrayList<>(inputStreams.keySet());
205 Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
206 Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap,
209 for (InputStream is : inputStreams.keySet()) {
212 } catch (IOException e) {
213 LOG.debug("Failed to close stream.");
217 Map<File, Module> result = new LinkedHashMap<>();
218 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
219 Set<ModuleBuilder> keyset = builderToModuleMap.keySet();
220 List<ModuleBuilder> sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()]));
221 for (ModuleBuilder key : sorted) {
222 result.put(inputStreams.get(builderToStreamMap.get(key)), builderToModuleMap.get(key));
228 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
229 if (yangModelStreams == null) {
230 return Collections.emptyMap();
233 Map<ModuleBuilder, InputStream> builderToStreamMap = new HashMap<>();
234 Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams, builderToStreamMap,
236 Map<InputStream, Module> result = new LinkedHashMap<>();
237 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
238 Set<ModuleBuilder> keyset = builderToModuleMap.keySet();
239 List<ModuleBuilder> sorted = ModuleDependencySort.sort(keyset.toArray(new ModuleBuilder[keyset.size()]));
240 for (ModuleBuilder key : sorted) {
241 result.put(builderToStreamMap.get(key), builderToModuleMap.get(key));
247 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
248 return new SchemaContextImpl(modules);
251 private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
252 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
254 final ParseTreeWalker walker = new ParseTreeWalker();
255 final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
256 final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
259 new YangModelBasicValidator(walker).validate(new ArrayList<>(trees.values()));
261 YangParserListenerImpl yangModelParser;
262 for (Map.Entry<InputStream, ParseTree> entry : trees.entrySet()) {
263 yangModelParser = new YangParserListenerImpl();
264 walker.walk(yangModelParser, entry.getValue());
265 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
267 // We expect the order of trees and streams has to be the same
268 streamToBuilderMap.put(moduleBuilder, entry.getKey());
269 builders.put(entry.getKey(), moduleBuilder);
275 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
276 final Map<ModuleBuilder, InputStream> streamToBuilderMap, 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);
288 return orderModules(sorted);
292 * Order modules by name and revision.
296 * @return modules ordered by name and revision
298 private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(List<ModuleBuilder> modules) {
299 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
300 for (final ModuleBuilder builder : modules) {
301 if (builder == null) {
304 final String builderName = builder.getName();
305 Date builderRevision = builder.getRevision();
306 if (builderRevision == null) {
307 builderRevision = new Date(0L);
309 TreeMap<Date, ModuleBuilder> builderByRevision = result.get(builderName);
310 if (builderByRevision == null) {
311 builderByRevision = new TreeMap<>();
313 builderByRevision.put(builderRevision, builder);
314 result.put(builderName, builderByRevision);
319 private void filterImports(ModuleBuilder main, List<ModuleBuilder> other, List<ModuleBuilder> filtered) {
320 for (ModuleImport mi : main.getModuleImports()) {
321 for (ModuleBuilder builder : other) {
322 if (mi.getModuleName().equals(builder.getModuleName())) {
323 if (mi.getRevision() == null) {
324 if (!filtered.contains(builder)) {
325 filtered.add(builder);
326 filterImports(builder, other, filtered);
329 if (mi.getRevision().equals(builder.getRevision())) {
330 if (!filtered.contains(builder)) {
331 filtered.add(builder);
332 filterImports(builder, other, filtered);
341 private Map<InputStream, ParseTree> parseStreams(final List<InputStream> yangStreams) {
342 final Map<InputStream, ParseTree> trees = new HashMap<>();
343 for (InputStream yangStream : yangStreams) {
344 trees.put(yangStream, parseStream(yangStream));
349 private ParseTree parseStream(final InputStream yangStream) {
350 ParseTree result = null;
352 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
353 final YangLexer lexer = new YangLexer(input);
354 final CommonTokenStream tokens = new CommonTokenStream(lexer);
355 final YangParser parser = new YangParser(tokens);
356 parser.removeErrorListeners();
357 YangErrorListener errorListener = new YangErrorListener();
358 parser.addErrorListener(errorListener);
359 result = parser.yang();
360 errorListener.validate();
361 } catch (IOException e) {
362 LOG.warn("Exception while reading yang file: " + yangStream, e);
367 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
368 // fix unresolved nodes
369 resolveDirtyNodes(modules);
370 resolveAugmentsTargetPath(modules, null);
371 resolveUsesTargetGrouping(modules, null);
372 resolveUsesForGroupings(modules, null);
373 resolveUsesForNodes(modules, null);
374 resolveAugments(modules, null);
375 resolveDeviations(modules);
378 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
379 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
380 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
381 final ModuleBuilder moduleBuilder = childEntry.getValue();
382 final Module module = moduleBuilder.build();
383 result.put(moduleBuilder, module);
389 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
390 final SchemaContext context) {
391 // fix unresolved nodes
392 resolvedDirtyNodesWithContext(modules, context);
393 resolveAugmentsTargetPath(modules, context);
394 resolveUsesTargetGrouping(modules, context);
395 resolveUsesForGroupings(modules, context);
396 resolveUsesForNodes(modules, context);
397 resolveAugments(modules, context);
398 resolveDeviationsWithContext(modules, context);
401 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
402 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
403 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
404 final ModuleBuilder moduleBuilder = childEntry.getValue();
405 final Module module = moduleBuilder.build();
406 result.put(moduleBuilder, module);
412 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
413 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
414 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
415 final ModuleBuilder module = childEntry.getValue();
416 resolveUnknownNodes(modules, module);
417 resolveIdentities(modules, module);
418 resolveDirtyNodes(modules, module);
423 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
424 final SchemaContext context) {
425 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
426 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
427 final ModuleBuilder module = childEntry.getValue();
428 resolveUnknownNodesWithContext(modules, module, context);
429 resolveIdentitiesWithContext(modules, module, context);
430 resolveDirtyNodesWithContext(modules, module, context);
436 * Search for dirty nodes (node which contains UnknownType) and resolve
440 * all available modules
444 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
445 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
446 if (!dirtyNodes.isEmpty()) {
447 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
448 if (nodeToResolve instanceof UnionTypeBuilder) {
449 // special handling for union types
450 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
451 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
452 // special handling for identityref types
453 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
454 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
456 if (identity == null) {
457 throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
459 idref.setBaseIdentity(identity);
460 nodeToResolve.setType(idref.build());
462 resolveType(nodeToResolve, modules, module);
468 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
469 final ModuleBuilder module, SchemaContext context) {
470 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
471 if (!dirtyNodes.isEmpty()) {
472 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
473 if (nodeToResolve instanceof UnionTypeBuilder) {
474 // special handling for union types
475 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
476 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
477 // special handling for identityref types
478 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
479 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
481 idref.setBaseIdentity(identity);
482 nodeToResolve.setType(idref.build());
484 resolveTypeWithContext(nodeToResolve, modules, module, context);
491 * Correct augment target path.
496 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
497 SchemaContext context) {
498 // collect augments from all loaded modules
499 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
500 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
501 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
502 allAugments.addAll(inner.getValue().getAllAugments());
506 for (AugmentationSchemaBuilder augment : allAugments) {
507 setCorrectAugmentTargetPath(modules, augment, context);
511 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
512 final AugmentationSchemaBuilder augment, final SchemaContext context) {
513 ModuleBuilder module = ParserUtils.getParentModule(augment);
514 SchemaPath oldSchemaPath = augment.getTargetPath();
515 List<QName> oldPath = oldSchemaPath.getPath();
516 List<QName> newPath = new ArrayList<>();
518 Builder parent = augment.getParent();
519 if (parent instanceof UsesNodeBuilder) {
520 DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
521 newPath.addAll(usesParent.getPath().getPath());
526 QName baseQName = usesParent.getQName();
527 if (baseQName == null) {
528 ModuleBuilder m = ParserUtils.getParentModule(usesParent);
529 ns = m.getNamespace();
530 revision = m.getRevision();
531 prefix = m.getPrefix();
533 ns = baseQName.getNamespace();
534 revision = baseQName.getRevision();
535 prefix = baseQName.getPrefix();
538 for (QName qn : oldSchemaPath.getPath()) {
539 newPath.add(new QName(ns, revision, prefix, qn.getLocalName()));
543 for (QName qn : oldPath) {
544 URI ns = module.getNamespace();
545 Date rev = module.getRevision();
546 String pref = module.getPrefix();
547 String localPrefix = qn.getPrefix();
548 if (localPrefix != null && !("".equals(localPrefix))) {
549 ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
551 if (currentModule == null) {
552 Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
554 throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
555 + localPrefix + " not found.");
557 ns = m.getNamespace();
558 rev = m.getRevision();
559 pref = m.getPrefix();
561 ns = currentModule.getNamespace();
562 rev = currentModule.getRevision();
563 pref = currentModule.getPrefix();
566 newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
569 augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
571 for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
572 correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
576 private void correctPathForAugmentNodes(DataSchemaNodeBuilder node, SchemaPath parentPath) {
577 SchemaPath newPath = ParserUtils.createSchemaPath(parentPath, node.getQName());
578 node.setPath(newPath);
579 if (node instanceof DataNodeContainerBuilder) {
580 for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) node).getChildNodes()) {
581 correctPathForAugmentNodes(child, node.getPath());
584 if (node instanceof ChoiceBuilder) {
585 for (ChoiceCaseBuilder child : ((ChoiceBuilder)node).getCases()) {
586 correctPathForAugmentNodes(child, node.getPath());
592 * Check augments for mandatory nodes. If the target node is in another
593 * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
594 * If mandatory node is found, throw an exception.
599 private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
600 for (AugmentationSchemaBuilder augment : augments) {
601 String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
602 ModuleBuilder module = ParserUtils.getParentModule(augment);
603 String modulePrefix = module.getPrefix();
605 if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
609 for (DataSchemaNodeBuilder childNode : augment.getChildNodes()) {
610 if (childNode.getConstraints().isMandatory()) {
611 throw new YangParseException(augment.getModuleName(), augment.getLine(),
612 "Error in augment parsing: cannot augment mandatory node "
613 + childNode.getQName().getLocalName());
620 * Go through all augment definitions and resolve them. This method works in
621 * same way as {@link #resolveAugments(Map)} except that if target node is
622 * not found in loaded modules, it search for target node in given context.
627 * SchemaContext containing already resolved modules
629 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
630 List<ModuleBuilder> all = new ArrayList<>();
631 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
632 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
633 all.add(inner.getValue());
637 List<ModuleBuilder> sorted;
638 if (context == null) {
639 sorted = ModuleDependencySort.sort(all.toArray(new ModuleBuilder[all.size()]));
641 sorted = ModuleDependencySort.sortWithContext(context, all.toArray(new ModuleBuilder[all.size()]));
644 // resolve other augments
645 for (ModuleBuilder mb : sorted) {
647 List<AugmentationSchemaBuilder> augments = mb.getAllAugments();
648 checkAugmentMandatoryNodes(augments);
649 for (AugmentationSchemaBuilder augment : augments) {
650 if (!(augment.isResolved())) {
651 boolean resolved = resolveAugment(augment, mb, modules, context);
653 throw new YangParseException(augment.getModuleName(), augment.getLine(),
654 "Error in augment parsing: failed to find augment target: " + augment);
663 private boolean resolveUsesAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
664 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
665 if (augment.isResolved()) {
669 UsesNodeBuilder usesNode = (UsesNodeBuilder) augment.getParent();
670 DataNodeContainerBuilder parentNode = usesNode.getParent();
671 SchemaNodeBuilder targetNode;
672 if (parentNode instanceof ModuleBuilder) {
673 targetNode = findSchemaNodeInModule(augment.getTargetPath().getPath(), (ModuleBuilder)parentNode);
675 targetNode = findSchemaNode(augment.getTargetPath().getPath(), (SchemaNodeBuilder)parentNode);
678 fillAugmentTarget(augment, targetNode);
679 augment.setResolved(true);
683 private boolean resolveAugment(final AugmentationSchemaBuilder augment, final ModuleBuilder module,
684 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
685 if (augment.isResolved()) {
689 List<QName> targetPath = augment.getTargetPath().getPath();
690 ModuleBuilder targetModule = findTargetModule(targetPath.get(0), module, modules, context, augment.getLine());
691 if (targetModule == null) {
692 throw new YangParseException(module.getModuleName(), augment.getLine(), "Failed to resolve augment "
696 return processAugmentation(augment, targetModule);
700 * Find module from loaded modules or from context based on given qname. If
701 * module is found in context, create wrapper over this module and add it to
702 * collection of loaded modules.
715 private ModuleBuilder findTargetModule(final QName qname, final ModuleBuilder module,
716 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context, final int line) {
717 ModuleBuilder targetModule = null;
719 String prefix = qname.getPrefix();
720 if (prefix == null || prefix.equals("")) {
721 targetModule = module;
723 targetModule = findModuleFromBuilders(modules, module, qname.getPrefix(), line);
726 if (targetModule == null && context != null) {
727 Module m = findModuleFromContext(context, module, prefix, line);
728 targetModule = new ModuleBuilder(m);
729 DataSchemaNode firstNode = m.getDataChildByName(qname.getLocalName());
730 DataSchemaNodeBuilder firstNodeWrapped = wrapChildNode(targetModule.getModuleName(), line, firstNode,
731 targetModule.getPath(), firstNode.getQName());
732 targetModule.addChildNode(firstNodeWrapped);
734 TreeMap<Date, ModuleBuilder> map = new TreeMap<>();
735 map.put(targetModule.getRevision(), targetModule);
736 modules.put(targetModule.getModuleName(), map);
743 * Go through identity statements defined in current module and resolve
744 * their 'base' statement if present.
749 * module being resolved
751 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
752 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
753 for (IdentitySchemaNodeBuilder identity : identities) {
754 final String baseIdentityName = identity.getBaseIdentityName();
755 final int line = identity.getLine();
756 if (baseIdentityName != null) {
757 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
758 if (baseIdentity == null) {
759 throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity");
761 identity.setBaseIdentity(baseIdentity);
768 * Go through identity statements defined in current module and resolve
769 * their 'base' statement. Method tries to find base identity in given
770 * modules. If base identity is not found, method will search it in context.
777 * SchemaContext containing already resolved modules
779 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
780 final ModuleBuilder module, final SchemaContext context) {
781 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
782 for (IdentitySchemaNodeBuilder identity : identities) {
783 final String baseIdentityName = identity.getBaseIdentityName();
784 final int line = identity.getLine();
785 if (baseIdentityName != null) {
786 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
787 if (baseIdentity == null) {
788 IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
790 identity.setBaseIdentity(baseId);
792 identity.setBaseIdentity(baseIdentity);
799 * Find and add reference of uses target grouping.
804 * SchemaContext containing already resolved modules or null if
805 * context is not available
807 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
808 final SchemaContext context) {
809 final List<UsesNodeBuilder> allUses = new ArrayList<>();
810 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
811 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
812 allUses.addAll(inner.getValue().getAllUsesNodes());
815 for (UsesNodeBuilder usesNode : allUses) {
816 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
817 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
819 if (targetGroupingBuilder == null) {
820 if (context == null) {
821 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
822 + usesNode.getGroupingPathAsString() + "' not found.");
824 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
826 usesNode.setGroupingDefinition(targetGroupingDefinition);
829 usesNode.setGrouping(targetGroupingBuilder);
834 private void resolveUsesForGroupings(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
835 final Set<GroupingBuilder> allGroupings = new HashSet<>();
836 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
837 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
838 ModuleBuilder module = inner.getValue();
839 allGroupings.addAll(module.getAllGroupings());
842 final List<GroupingBuilder> sorted = GroupingSort.sort(allGroupings);
843 for (GroupingBuilder gb : sorted) {
844 List<UsesNodeBuilder> usesNodes = new ArrayList<>(GroupingSort.getAllUsesNodes(gb));
845 Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
846 for (UsesNodeBuilder usesNode : usesNodes) {
847 resolveUses(usesNode, modules, context);
852 private void resolveUsesForNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
853 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
854 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
855 ModuleBuilder module = inner.getValue();
856 List<UsesNodeBuilder> usesNodes = module.getAllUsesNodes();
857 Collections.sort(usesNodes, new GroupingUtils.UsesComparator());
858 for (UsesNodeBuilder usesNode : usesNodes) {
859 resolveUses(usesNode, modules, context);
865 private void resolveUses(UsesNodeBuilder usesNode,
866 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
867 if (!usesNode.isResolved()) {
868 DataNodeContainerBuilder parent = usesNode.getParent();
869 ModuleBuilder module = ParserUtils.getParentModule(parent);
870 GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module);
871 if (target == null) {
872 resolveUsesWithContext(usesNode);
873 usesNode.setResolved(true);
874 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
875 resolveUsesAugment(augment, module, modules, context);
878 parent.getChildNodes().addAll(target.instantiateChildNodes(parent));
879 parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
880 parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
881 parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
882 usesNode.setResolved(true);
883 for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
884 resolveUsesAugment(augment, module, modules, context);
887 GroupingUtils.performRefine(usesNode);
891 private void resolveUsesWithContext(UsesNodeBuilder usesNode) {
892 final int line = usesNode.getLine();
893 DataNodeContainerBuilder parent = usesNode.getParent();
894 ModuleBuilder module = ParserUtils.getParentModule(parent);
895 SchemaPath parentPath;
899 if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) {
900 ns = module.getNamespace();
901 rev = module.getRevision();
902 pref = module.getPrefix();
903 if (parent instanceof AugmentationSchemaBuilder) {
904 parentPath = ((AugmentationSchemaBuilder)parent).getTargetNodeSchemaPath();
906 parentPath = ((ModuleBuilder)parent).getPath();
909 ns = ((DataSchemaNodeBuilder) parent).getQName().getNamespace();
910 rev = ((DataSchemaNodeBuilder) parent).getQName().getRevision();
911 pref = ((DataSchemaNodeBuilder) parent).getQName().getPrefix();
912 parentPath = ((DataSchemaNodeBuilder)parent).getPath();
915 GroupingDefinition gd = usesNode.getGroupingDefinition();
917 Set<DataSchemaNodeBuilder> childNodes = wrapChildNodes(module.getModuleName(), line,
918 gd.getChildNodes(), parentPath, ns, rev, pref);
919 parent.getChildNodes().addAll(childNodes);
920 for (DataSchemaNodeBuilder childNode : childNodes) {
921 setNodeAddedByUses(childNode);
924 Set<TypeDefinitionBuilder> typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, ns,
926 parent.getTypeDefinitionBuilders().addAll(typedefs);
927 for (TypeDefinitionBuilder typedef : typedefs) {
928 setNodeAddedByUses(typedef);
931 Set<GroupingBuilder> groupings = wrapGroupings(module.getModuleName(), line, usesNode
932 .getGroupingDefinition().getGroupings(), parentPath, ns, rev, pref);
933 parent.getGroupingBuilders().addAll(groupings);
934 for (GroupingBuilder gb : groupings) {
935 setNodeAddedByUses(gb);
938 List<UnknownSchemaNodeBuilder> unknownNodes = wrapUnknownNodes(module.getModuleName(), line,
939 gd.getUnknownSchemaNodes(), parentPath, ns, rev, pref);
940 parent.getUnknownNodes().addAll(unknownNodes);
941 for (UnknownSchemaNodeBuilder un : unknownNodes) {
942 un.setAddedByUses(true);
946 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
947 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
948 QName nodeType = usnb.getNodeType();
950 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
952 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
953 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
954 usnb.setNodeType(extension.getQName());
955 usnb.setExtensionBuilder(extension);
959 } catch (YangParseException e) {
960 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
961 + ": no such extension definition found.", e);
966 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
967 final ModuleBuilder module, final SchemaContext context) {
968 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
969 QName nodeType = usnb.getNodeType();
971 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
974 if (dependentModuleBuilder == null) {
975 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
977 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
978 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
979 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
980 nodeType.getPrefix(), e.getQName().getLocalName()));
981 usnb.setExtensionDefinition(e);
986 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
987 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
988 usnb.setExtensionBuilder(extension);
994 } catch (YangParseException e) {
995 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
996 + ": no such extension definition found.", e);
1003 * Traverse through modules and resolve their deviation statements.
1006 * all loaded modules
1008 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
1009 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1010 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1011 ModuleBuilder b = inner.getValue();
1012 resolveDeviation(modules, b);
1018 * Traverse through module and resolve its deviation statements.
1021 * all loaded modules
1023 * module in which resolve deviations
1025 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1026 for (DeviationBuilder dev : module.getDeviations()) {
1027 int line = dev.getLine();
1028 SchemaPath targetPath = dev.getTargetPath();
1029 List<QName> path = targetPath.getPath();
1030 QName q0 = path.get(0);
1031 String prefix = q0.getPrefix();
1032 if (prefix == null) {
1033 prefix = module.getPrefix();
1036 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1037 processDeviation(dev, dependentModuleBuilder, path, module);
1042 * Traverse through modules and resolve their deviation statements with
1046 * all loaded modules
1048 * already resolved context
1050 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1051 final SchemaContext context) {
1052 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1053 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1054 ModuleBuilder b = inner.getValue();
1055 resolveDeviationWithContext(modules, b, context);
1061 * Traverse through module and resolve its deviation statements with given
1065 * all loaded modules
1067 * module in which resolve deviations
1069 * already resolved context
1071 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1072 final ModuleBuilder module, final SchemaContext context) {
1073 for (DeviationBuilder dev : module.getDeviations()) {
1074 int line = dev.getLine();
1075 SchemaPath targetPath = dev.getTargetPath();
1076 List<QName> path = targetPath.getPath();
1077 QName q0 = path.get(0);
1078 String prefix = q0.getPrefix();
1079 if (prefix == null) {
1080 prefix = module.getPrefix();
1083 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1084 if (dependentModuleBuilder == null) {
1085 Object currentParent = findModuleFromContext(context, module, prefix, line);
1087 for (QName q : path) {
1088 if (currentParent == null) {
1089 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1091 String name = q.getLocalName();
1092 if (currentParent instanceof DataNodeContainer) {
1093 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1097 if (currentParent == null) {
1098 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1100 if (currentParent instanceof SchemaNode) {
1101 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1105 processDeviation(dev, dependentModuleBuilder, path, module);
1111 * Correct deviation target path in deviation builder.
1115 * @param dependentModuleBuilder
1116 * module containing deviation target
1118 * current deviation target path
1122 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1123 final List<QName> path, final ModuleBuilder module) {
1124 final int line = dev.getLine();
1125 Builder currentParent = dependentModuleBuilder;
1127 for (QName q : path) {
1128 if (currentParent == null) {
1129 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1131 String name = q.getLocalName();
1132 if (currentParent instanceof DataNodeContainerBuilder) {
1133 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1137 if (!(currentParent instanceof SchemaNodeBuilder)) {
1138 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1140 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());