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.*;
14 import java.io.FileInputStream;
15 import java.io.FileNotFoundException;
16 import java.io.IOException;
17 import java.io.InputStream;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.Date;
23 import java.util.HashMap;
24 import java.util.LinkedHashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
28 import java.util.Map.Entry;
30 import java.util.TreeMap;
32 import org.antlr.v4.runtime.ANTLRInputStream;
33 import org.antlr.v4.runtime.CommonTokenStream;
34 import org.antlr.v4.runtime.tree.ParseTree;
35 import org.antlr.v4.runtime.tree.ParseTreeWalker;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
38 import org.opendaylight.yangtools.yang.common.QName;
39 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
40 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
41 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
42 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.Module;
44 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
45 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
46 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
48 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
49 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
65 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
66 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
67 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
68 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
72 import com.google.common.base.Preconditions;
73 import com.google.common.collect.Lists;
74 import com.google.common.collect.Maps;
75 import com.google.common.collect.Sets;
77 public final class YangParserImpl implements YangModelParser {
78 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
80 private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
83 public Set<Module> parseYangModels(final File yangFile, final File directory) {
84 Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
85 Preconditions.checkState(directory.exists(), directory + " does not exists");
86 Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
88 final String yangFileName = yangFile.getName();
89 final String[] fileList = directory.list();
90 Preconditions.checkNotNull(fileList, directory + " not found");
92 FileInputStream yangFileStream = null;
93 LinkedHashMap<InputStream, File> streamToFileMap = new LinkedHashMap<>();
96 yangFileStream = new FileInputStream(yangFile);
97 streamToFileMap.put(yangFileStream, yangFile);
98 } catch(FileNotFoundException e) {
99 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
102 for (String fileName : fileList) {
103 if (fileName.equals(yangFileName)) {
106 File dependency = new File(directory, fileName);
108 if (dependency.isFile()) {
109 streamToFileMap.put(new FileInputStream(dependency), dependency);
111 } catch(FileNotFoundException e) {
112 LOG.warn("Exception while reading yang file: " + fileName, e);
116 Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(
117 new ArrayList<>(streamToFileMap.keySet()), new HashMap<ModuleBuilder, InputStream>());
118 ModuleBuilder main = parsedBuilders.get(yangFileStream);
120 List<ModuleBuilder> moduleBuilders = new ArrayList<>();
121 moduleBuilders.add(main);
122 filterImports(main, new ArrayList<>(parsedBuilders.values()), moduleBuilders);
124 ModuleBuilder[] builders = new ModuleBuilder[moduleBuilders.size()];
125 moduleBuilders.toArray(builders);
127 // module dependency graph sorted
128 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
130 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
131 return new LinkedHashSet<>(build(modules).values());
135 public Set<Module> parseYangModels(final List<File> yangFiles) {
136 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
140 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
141 if (yangFiles != null) {
142 final Map<InputStream, File> inputStreams = Maps.newHashMap();
144 for (final File yangFile : yangFiles) {
146 inputStreams.put(new FileInputStream(yangFile), yangFile);
147 } catch (FileNotFoundException e) {
148 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
152 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
153 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
154 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
156 for (InputStream is : inputStreams.keySet()) {
159 } catch (IOException e) {
160 LOG.debug("Failed to close stream.");
164 return new LinkedHashSet<>(buildWithContext(modules, context).values());
166 return Collections.emptySet();
170 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
171 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
175 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
176 if (yangModelStreams != null) {
177 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
178 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
179 yangModelStreams, builderToStreamMap, context);
180 return new LinkedHashSet<>(buildWithContext(modules, context).values());
182 return Collections.emptySet();
186 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
187 if (yangFiles != null) {
188 final Map<InputStream, File> inputStreams = Maps.newHashMap();
190 for (final File yangFile : yangFiles) {
192 inputStreams.put(new FileInputStream(yangFile), yangFile);
193 } catch (FileNotFoundException e) {
194 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
198 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
199 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
200 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
202 for (InputStream is : inputStreams.keySet()) {
205 } catch (IOException e) {
206 LOG.debug("Failed to close stream.");
210 Map<File, Module> retVal = Maps.newLinkedHashMap();
211 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
213 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
214 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
215 builderToModule.getValue());
220 return Collections.emptyMap();
224 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
225 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
227 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
229 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
230 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
232 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
233 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
239 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
240 return new SchemaContextImpl(modules);
243 private Map<InputStream, ModuleBuilder> parseModuleBuilders(List<InputStream> inputStreams,
244 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
246 final ParseTreeWalker walker = new ParseTreeWalker();
247 final Map<InputStream, ParseTree> trees = parseStreams(inputStreams);
248 final Map<InputStream, ModuleBuilder> builders = new LinkedHashMap<>();
251 new YangModelBasicValidator(walker).validate(new ArrayList<>(trees.values()));
253 YangParserListenerImpl yangModelParser;
254 for(Map.Entry<InputStream, ParseTree> entry : trees.entrySet()) {
255 yangModelParser = new YangParserListenerImpl();
256 walker.walk(yangModelParser, entry.getValue());
257 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
259 // We expect the order of trees and streams has to be the same
260 streamToBuilderMap.put(moduleBuilder, entry.getKey());
261 builders.put(entry.getKey(), moduleBuilder);
267 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
268 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
269 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
272 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
273 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
274 final SchemaContext context) {
275 Map<InputStream, ModuleBuilder> parsedBuilders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
276 ModuleBuilder[] builders = new ModuleBuilder[parsedBuilders.size()];
277 parsedBuilders.values().toArray(builders);
279 // module dependency graph sorted
280 List<ModuleBuilder> sorted;
281 if (context == null) {
282 sorted = ModuleDependencySort.sort(builders);
284 sorted = ModuleDependencySort.sortWithContext(context, builders);
287 return orderModules(sorted);
291 * Order modules by name and revision.
295 * @return modules ordered by name and revision
297 private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(List<ModuleBuilder> modules) {
298 // LinkedHashMap must be used to preserve order
299 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 parser.addErrorListener(new YangErrorListener());
359 result = parser.yang();
360 } catch (IOException e) {
361 LOG.warn("Exception while reading yang file: " + yangStream, e);
366 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
367 // fix unresolved nodes
368 resolveAugmentsTargetPath(modules, null);
369 resolveUsesTargetGrouping(modules, null);
370 resolveDirtyNodes(modules);
371 resolveAugments(modules);
372 resolveUses(modules, false);
373 resolvedUsesPostProcessing(modules, false);
374 resolveDeviations(modules);
377 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
378 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
379 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
380 final ModuleBuilder moduleBuilder = childEntry.getValue();
381 final Module module = moduleBuilder.build();
382 result.put(moduleBuilder, module);
388 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
389 final SchemaContext context) {
390 // fix unresolved nodes
391 resolveAugmentsTargetPath(modules, context);
392 resolveUsesTargetGrouping(modules, context);
393 resolvedDirtyNodesWithContext(modules, context);
394 resolveAugmentsWithContext(modules, context);
395 resolveUses(modules, true);
396 resolvedUsesPostProcessing(modules, true);
397 resolveDeviationsWithContext(modules, context);
400 final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
401 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
402 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
403 final ModuleBuilder moduleBuilder = childEntry.getValue();
404 final Module module = moduleBuilder.build();
405 result.put(moduleBuilder, module);
411 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
412 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
413 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
414 final ModuleBuilder module = childEntry.getValue();
415 resolveUnknownNodes(modules, module);
416 resolveIdentities(modules, module);
417 resolveDirtyNodes(modules, module);
422 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
423 final SchemaContext context) {
424 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
425 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
426 final ModuleBuilder module = childEntry.getValue();
427 resolveUnknownNodesWithContext(modules, module, context);
428 resolveIdentitiesWithContext(modules, module, context);
429 resolveDirtyNodesWithContext(modules, module, context);
435 * Search for dirty nodes (node which contains UnknownType) and resolve
439 * all available modules
443 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
444 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
445 if (!dirtyNodes.isEmpty()) {
446 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
447 if (nodeToResolve instanceof UnionTypeBuilder) {
448 // special handling for union types
449 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
450 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
451 // special handling for identityref types
452 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
453 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
455 if (identity == null) {
456 throw new YangParseException(module.getName(), idref.getLine(), "Failed to find base identity");
458 idref.setBaseIdentity(identity);
459 nodeToResolve.setType(idref.build(null));
461 resolveType(nodeToResolve, modules, module);
467 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
468 final ModuleBuilder module, SchemaContext context) {
469 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
470 if (!dirtyNodes.isEmpty()) {
471 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
472 if (nodeToResolve instanceof UnionTypeBuilder) {
473 // special handling for union types
474 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
475 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
476 // special handling for identityref types
477 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
478 IdentitySchemaNodeBuilder identity = findBaseIdentity(modules, module, idref.getBaseString(),
480 idref.setBaseIdentity(identity);
481 nodeToResolve.setType(idref.build(null));
483 resolveTypeWithContext(nodeToResolve, modules, module, context);
490 * Correct augment target path.
495 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
496 SchemaContext context) {
497 // collect augments from all loaded modules
498 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
499 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
500 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
501 allAugments.addAll(inner.getValue().getAllAugments());
505 for (AugmentationSchemaBuilder augment : allAugments) {
506 setCorrectAugmentTargetPath(modules, augment, context);
510 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
511 final AugmentationSchemaBuilder augment, final SchemaContext context) {
512 ModuleBuilder module = ParserUtils.getParentModule(augment);
513 SchemaPath oldSchemaPath = augment.getTargetPath();
514 List<QName> oldPath = oldSchemaPath.getPath();
515 List<QName> newPath = new ArrayList<>();
516 for (QName qn : oldPath) {
517 URI ns = module.getNamespace();
518 Date rev = module.getRevision();
519 String pref = module.getPrefix();
520 String localPrefix = qn.getPrefix();
521 if (localPrefix != null && !("".equals(localPrefix))) {
522 ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
524 if (currentModule == null) {
525 Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
527 throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
528 + localPrefix + " not found.");
530 ns = m.getNamespace();
531 rev = m.getRevision();
532 pref = m.getPrefix();
534 ns = currentModule.getNamespace();
535 rev = currentModule.getRevision();
536 pref = currentModule.getPrefix();
539 newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
541 augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
545 * Go through all augment definitions and perform augmentation. It is
546 * expected that modules are already sorted by their dependencies.
551 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
552 // collect augments from all loaded modules
553 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
554 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
555 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
556 allAugments.addAll(inner.getValue().getAllAugments());
560 checkAugmentMandatoryNodes(allAugments);
562 for (int i = 0; i < allAugments.size(); i++) {
564 final AugmentationSchemaBuilder augment = allAugments.get(i);
565 // create collection of others
566 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
567 others.remove(augment);
570 boolean resolved = resolveAugment(modules, augment);
571 // while not resolved
573 while (!(resolved) && j < others.size()) {
574 // try to resolve next augment
575 resolveAugment(modules, others.get(j));
576 // then try to resolve first again
577 resolved = resolveAugment(modules, augment);
583 throw new YangParseException(augment.getModuleName(), augment.getLine(),
584 "Error in augment parsing: failed to find augment target");
590 * Check augments for mandatory nodes. If the target node is in another
591 * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
592 * If mandatory node is found, throw an exception.
597 private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
598 for (AugmentationSchemaBuilder augment : augments) {
599 String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
600 ModuleBuilder module = ParserUtils.getParentModule(augment);
601 String modulePrefix = module.getPrefix();
603 if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
607 for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
608 if (childNode.getConstraints().isMandatory()) {
609 throw new YangParseException(augment.getModuleName(), augment.getLine(),
610 "Error in augment parsing: cannot augment mandatory node");
617 * Search for augment target and perform augmentation.
623 * @return true if target node found, false otherwise
625 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
626 final AugmentationSchemaBuilder augment) {
627 if (augment.isResolved()) {
631 int line = augment.getLine();
632 ModuleBuilder module = getParentModule(augment);
633 List<QName> path = augment.getTargetPath().getPath();
634 Builder augmentParent = augment.getParent();
636 Builder firstNodeParent;
637 if (augmentParent instanceof ModuleBuilder) {
638 // if augment is defined under module, parent of first node is
640 final QName firstNameInPath = path.get(0);
641 String prefix = firstNameInPath.getPrefix();
642 if (prefix == null) {
643 prefix = module.getPrefix();
645 firstNodeParent = findModuleFromBuilders(modules, module, prefix, line);
646 } else if (augmentParent instanceof UsesNodeBuilder) {
647 firstNodeParent = augmentParent.getParent();
649 // augment can be defined only under module or uses
650 throw new YangParseException(augment.getModuleName(), line,
651 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
654 return processAugmentation(augment, firstNodeParent, path);
658 * Go through all augment definitions and resolve them. This method works in
659 * same way as {@link #resolveAugments(Map)} except that if target node is
660 * not found in loaded modules, it search for target node in given context.
665 * SchemaContext containing already resolved modules
667 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
668 final SchemaContext context) {
669 // collect augments from all loaded modules
670 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
671 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
672 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
673 allAugments.addAll(inner.getValue().getAllAugments());
677 for (int i = 0; i < allAugments.size(); i++) {
678 // pick augment from list
679 final AugmentationSchemaBuilder augment = allAugments.get(i);
681 boolean resolved = resolveAugmentWithContext(modules, augment, context);
682 // while not resolved
684 while (!(resolved) && j < allAugments.size()) {
685 // try to resolve next augment
686 resolveAugmentWithContext(modules, allAugments.get(j), context);
687 // then try to resolve first again
688 resolved = resolveAugmentWithContext(modules, augment, context);
693 throw new YangParseException(augment.getModuleName(), augment.getLine(),
694 "Error in augment parsing: failed to find augment target");
700 * Search for augment target and perform augmentation.
707 * SchemaContext containing already resolved modules
708 * @return true if target node found, false otherwise
710 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
711 final AugmentationSchemaBuilder augment, final SchemaContext context) {
712 if (augment.isResolved()) {
715 int line = augment.getLine();
716 ModuleBuilder module = getParentModule(augment);
717 List<QName> path = augment.getTargetNodeSchemaPath().getPath();
718 final QName firstNameInPath = path.get(0);
719 String prefix = firstNameInPath.getPrefix();
720 if (prefix == null) {
721 prefix = module.getPrefix();
723 Builder augmentParent = augment.getParent();
724 Builder currentParent;
725 if (augmentParent instanceof ModuleBuilder) {
726 // if augment is defined under module, first parent is target module
727 currentParent = findModuleFromBuilders(modules, module, prefix, line);
728 } else if (augmentParent instanceof UsesNodeBuilder) {
729 currentParent = augmentParent.getParent();
731 // augment can be defined only under module or uses
732 throw new YangParseException(augment.getModuleName(), augment.getLine(),
733 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
736 if (currentParent == null) {
737 return processAugmentationOnContext(augment, path, module, prefix, context);
739 return processAugmentation(augment, currentParent, path);
744 * Go through identity statements defined in current module and resolve
745 * their 'base' statement if present.
750 * module being resolved
752 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
753 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
754 for (IdentitySchemaNodeBuilder identity : identities) {
755 final String baseIdentityName = identity.getBaseIdentityName();
756 final int line = identity.getLine();
757 if (baseIdentityName != null) {
758 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
759 if (baseIdentity == null) {
760 throw new YangParseException(module.getName(), identity.getLine(), "Failed to find base identity");
762 identity.setBaseIdentity(baseIdentity);
769 * Go through identity statements defined in current module and resolve
770 * their 'base' statement. Method tries to find base identity in given
771 * modules. If base identity is not found, method will search it in context.
778 * SchemaContext containing already resolved modules
780 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
781 final ModuleBuilder module, final SchemaContext context) {
782 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
783 for (IdentitySchemaNodeBuilder identity : identities) {
784 final String baseIdentityName = identity.getBaseIdentityName();
785 final int line = identity.getLine();
786 if (baseIdentityName != null) {
787 IdentitySchemaNodeBuilder baseIdentity = findBaseIdentity(modules, module, baseIdentityName, line);
788 if (baseIdentity == null) {
789 IdentitySchemaNode baseId = findBaseIdentityFromContext(modules, module, baseIdentityName, line,
791 identity.setBaseIdentity(baseId);
793 identity.setBaseIdentity(baseIdentity);
800 * Find and add reference of uses target grouping.
805 * SchemaContext containing already resolved modules or null if
806 * context is not available
808 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
809 final SchemaContext context) {
810 final List<UsesNodeBuilder> allUses = new ArrayList<>();
811 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
812 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
813 allUses.addAll(inner.getValue().getAllUsesNodes());
816 for (UsesNodeBuilder usesNode : allUses) {
817 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
818 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
820 if (targetGroupingBuilder == null) {
821 if (context == null) {
822 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
823 + usesNode.getGroupingPathAsString() + "' not found.");
825 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
827 usesNode.setGroupingDefinition(targetGroupingDefinition);
830 usesNode.setGrouping(targetGroupingBuilder);
836 * Copy data from uses target. Augmentations have to be resolved already.
840 * @param resolveWithContext
841 * boolean value which says whether
842 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
843 * collectUsesDataFromContext} should be used for processing of
844 * individual uses node.
846 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final boolean resolveWithContext) {
847 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
848 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
849 ModuleBuilder module = inner.getValue();
850 boolean dataCollected = module.isAllUsesDataCollected();
852 List<UsesNodeBuilder> usesNodes;
853 while (!dataCollected) {
854 usesNodes = new ArrayList<>(module.getAllUsesNodes());
855 for (UsesNodeBuilder usesNode : usesNodes) {
856 if (!usesNode.isDataCollected()) {
857 if (resolveWithContext && usesNode.getGroupingBuilder() == null) {
858 GroupingUtils.collectUsesDataFromContext(usesNode);
860 GroupingUtils.collectUsesData(usesNode);
864 dataCollected = module.isAllUsesDataCollected();
871 * Update uses parent and perform refinement.
875 * @param resolveWithContext
876 * boolean value which says whether
877 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
878 * collectUsesDataFromContext} should be used for processing of
879 * individual uses node.
881 private void resolvedUsesPostProcessing(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
882 final boolean resolveWithContext) {
883 // new loop is must because in collecting data process new uses could
885 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
886 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
887 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
888 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
892 for (UsesNodeBuilder usesNode : allModulesUses) {
893 GroupingUtils.updateUsesParent(usesNode);
894 GroupingUtils.performRefine(usesNode);
897 if (!resolveWithContext) {
898 for (UsesNodeBuilder usesNode : allModulesUses) {
899 if (usesNode.isCopy()) {
900 usesNode.getParent().getUsesNodes().remove(usesNode);
906 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
907 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
908 QName nodeType = usnb.getNodeType();
910 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
912 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
913 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
914 usnb.setNodeType(extension.getQName());
915 usnb.setExtensionBuilder(extension);
919 } catch (YangParseException e) {
920 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
921 + ": no such extension definition found.", e);
926 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
927 final ModuleBuilder module, final SchemaContext context) {
928 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
929 QName nodeType = usnb.getNodeType();
931 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
932 nodeType.getPrefix(), usnb.getLine());
934 if (dependentModuleBuilder == null) {
935 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
937 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
938 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
939 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
940 nodeType.getPrefix(), e.getQName().getLocalName()));
941 usnb.setExtensionDefinition(e);
946 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
947 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
948 usnb.setExtensionBuilder(extension);
954 } catch (YangParseException e) {
955 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
956 + ": no such extension definition found.", e);
963 * Traverse through modules and resolve their deviation statements.
968 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
969 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
970 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
971 ModuleBuilder b = inner.getValue();
972 resolveDeviation(modules, b);
978 * Traverse through module and resolve its deviation statements.
983 * module in which resolve deviations
985 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
986 for (DeviationBuilder dev : module.getDeviations()) {
987 int line = dev.getLine();
988 SchemaPath targetPath = dev.getTargetPath();
989 List<QName> path = targetPath.getPath();
990 QName q0 = path.get(0);
991 String prefix = q0.getPrefix();
992 if (prefix == null) {
993 prefix = module.getPrefix();
996 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
997 processDeviation(dev, dependentModuleBuilder, path, module);
1002 * Traverse through modules and resolve their deviation statements with
1006 * all loaded modules
1008 * already resolved context
1010 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1011 final SchemaContext context) {
1012 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1013 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1014 ModuleBuilder b = inner.getValue();
1015 resolveDeviationWithContext(modules, b, context);
1021 * Traverse through module and resolve its deviation statements with given
1025 * all loaded modules
1027 * module in which resolve deviations
1029 * already resolved context
1031 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1032 final ModuleBuilder module, final SchemaContext context) {
1033 for (DeviationBuilder dev : module.getDeviations()) {
1034 int line = dev.getLine();
1035 SchemaPath targetPath = dev.getTargetPath();
1036 List<QName> path = targetPath.getPath();
1037 QName q0 = path.get(0);
1038 String prefix = q0.getPrefix();
1039 if (prefix == null) {
1040 prefix = module.getPrefix();
1043 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1044 if (dependentModuleBuilder == null) {
1045 Object currentParent = findModuleFromContext(context, module, prefix, line);
1047 for (QName q : path) {
1048 if (currentParent == null) {
1049 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1051 String name = q.getLocalName();
1052 if (currentParent instanceof DataNodeContainer) {
1053 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1057 if (currentParent == null) {
1058 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1060 if (currentParent instanceof SchemaNode) {
1061 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1065 processDeviation(dev, dependentModuleBuilder, path, module);
1071 * Correct deviation target path in deviation builder.
1075 * @param dependentModuleBuilder
1076 * module containing deviation target
1078 * current deviation target path
1082 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1083 final List<QName> path, final ModuleBuilder module) {
1084 final int line = dev.getLine();
1085 Builder currentParent = dependentModuleBuilder;
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 DataNodeContainerBuilder) {
1093 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1097 if (!(currentParent instanceof SchemaNodeBuilder)) {
1098 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1100 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());