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;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.LinkedHashMap;
24 import java.util.LinkedHashSet;
25 import java.util.List;
27 import java.util.Map.Entry;
29 import java.util.TreeMap;
31 import org.antlr.v4.runtime.ANTLRInputStream;
32 import org.antlr.v4.runtime.CommonTokenStream;
33 import org.antlr.v4.runtime.tree.ParseTree;
34 import org.antlr.v4.runtime.tree.ParseTreeWalker;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
37 import org.opendaylight.yangtools.yang.common.QName;
38 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
39 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
40 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
41 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.Module;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
46 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
47 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
48 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
63 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
64 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
65 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
66 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
67 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
71 import com.google.common.collect.Lists;
72 import com.google.common.collect.Maps;
73 import com.google.common.collect.Sets;
75 public final class YangParserImpl implements YangModelParser {
76 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
78 private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
81 public Set<Module> parseYangModels(final List<File> yangFiles) {
82 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
86 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
87 if (yangFiles != null) {
88 final Map<InputStream, File> inputStreams = Maps.newHashMap();
90 for (final File yangFile : yangFiles) {
92 inputStreams.put(new FileInputStream(yangFile), yangFile);
93 } catch (FileNotFoundException e) {
94 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
98 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
100 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
101 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
103 for (InputStream is : inputStreams.keySet()) {
106 } catch (IOException e) {
107 LOG.debug("Failed to close stream.");
111 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
113 return Collections.emptySet();
117 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
118 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
122 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
123 if (yangModelStreams != null) {
124 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
125 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
126 yangModelStreams, builderToStreamMap, context);
127 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
129 return Collections.emptySet();
133 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
134 if (yangFiles != null) {
135 final Map<InputStream, File> inputStreams = Maps.newHashMap();
137 for (final File yangFile : yangFiles) {
139 inputStreams.put(new FileInputStream(yangFile), yangFile);
140 } catch (FileNotFoundException e) {
141 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
145 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
146 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
147 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
149 for (InputStream is : inputStreams.keySet()) {
152 } catch (IOException e) {
153 LOG.debug("Failed to close stream.");
157 Map<File, Module> retVal = Maps.newLinkedHashMap();
158 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
160 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
161 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
162 builderToModule.getValue());
167 return Collections.emptyMap();
171 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
172 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
174 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
176 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
177 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
179 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
180 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
186 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
187 return new SchemaContextImpl(modules);
190 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
191 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
193 final ParseTreeWalker walker = new ParseTreeWalker();
194 final List<ParseTree> trees = parseStreams(inputStreams);
195 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
198 new YangModelBasicValidator(walker).validate(trees);
200 YangParserListenerImpl yangModelParser = null;
201 for (int i = 0; i < trees.size(); i++) {
202 yangModelParser = new YangParserListenerImpl();
203 walker.walk(yangModelParser, trees.get(i));
204 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
206 // We expect the order of trees and streams has to be the same
207 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
208 builders[i] = moduleBuilder;
213 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
214 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
215 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
218 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
219 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
220 final SchemaContext context) {
221 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
223 // LinkedHashMap must be used to preserve order
224 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
226 // module dependency graph sorted
227 List<ModuleBuilder> sorted = null;
228 if (context == null) {
229 sorted = ModuleDependencySort.sort(builders);
231 sorted = ModuleDependencySort.sortWithContext(context, builders);
234 for (final ModuleBuilder builder : sorted) {
235 if (builder == null) {
238 final String builderName = builder.getName();
239 Date builderRevision = builder.getRevision();
240 if (builderRevision == null) {
241 builderRevision = new Date(0L);
243 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
244 if (builderByRevision == null) {
245 builderByRevision = new TreeMap<Date, ModuleBuilder>();
247 builderByRevision.put(builderRevision, builder);
248 modules.put(builderName, builderByRevision);
253 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
254 final List<ParseTree> trees = new ArrayList<ParseTree>();
255 for (InputStream yangStream : yangStreams) {
256 trees.add(parseStream(yangStream));
261 private ParseTree parseStream(final InputStream yangStream) {
262 ParseTree result = null;
264 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
265 final YangLexer lexer = new YangLexer(input);
266 final CommonTokenStream tokens = new CommonTokenStream(lexer);
267 final YangParser parser = new YangParser(tokens);
268 parser.removeErrorListeners();
269 parser.addErrorListener(new YangErrorListener());
271 result = parser.yang();
272 } catch (IOException e) {
273 LOG.warn("Exception while reading yang file: " + yangStream, e);
278 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
279 // fix unresolved nodes
280 resolveAugmentsTargetPath(modules);
281 resolveUsesTargetGrouping(modules, null);
282 resolveDirtyNodes(modules);
283 resolveAugments(modules);
284 resolveUses(modules, false);
285 resolvedUsesPostProcessing(modules, false);
286 resolveDeviations(modules);
289 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
290 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
291 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
292 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
293 final ModuleBuilder moduleBuilder = childEntry.getValue();
294 final Module module = moduleBuilder.build();
295 modulesByRevision.put(childEntry.getKey(), module);
296 result.put(moduleBuilder, module);
302 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
303 final SchemaContext context) {
304 // fix unresolved nodes
306 // fixAugmentsTargetPath(modules);
307 resolveUsesTargetGrouping(modules, context);
308 resolvedDirtyNodesWithContext(modules, context);
309 resolveAugmentsWithContext(modules, context);
310 resolveUses(modules, true);
311 resolveDeviationsWithContext(modules, context);
314 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
315 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
316 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
317 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
318 final ModuleBuilder moduleBuilder = childEntry.getValue();
319 final Module module = moduleBuilder.build();
320 modulesByRevision.put(childEntry.getKey(), module);
321 result.put(moduleBuilder, module);
327 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
328 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
329 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
330 final ModuleBuilder module = childEntry.getValue();
331 resolveDirtyNodes(modules, module);
332 resolveIdentities(modules, module);
333 resolveUnknownNodes(modules, module);
338 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
339 final SchemaContext context) {
340 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
341 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
342 final ModuleBuilder module = childEntry.getValue();
343 resolveDirtyNodesWithContext(modules, module, context);
344 resolveIdentitiesWithContext(modules, module, context);
345 resolveUnknownNodesWithContext(modules, module, context);
351 * Search for dirty nodes (node which contains UnknownType) and resolve
355 * all available modules
359 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
360 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
361 if (!dirtyNodes.isEmpty()) {
362 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
363 if (nodeToResolve instanceof UnionTypeBuilder) {
364 // special handling for union types
365 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
366 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
367 // special handling for identityref types
368 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
369 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
371 resolveType(nodeToResolve, modules, module);
377 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
378 final ModuleBuilder module, SchemaContext context) {
379 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
380 if (!dirtyNodes.isEmpty()) {
381 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
382 if (nodeToResolve instanceof UnionTypeBuilder) {
383 // special handling for union types
384 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
385 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
386 // special handling for identityref types
387 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
388 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
390 resolveTypeWithContext(nodeToResolve, modules, module, context);
397 * Correct augment target path.
402 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
403 // collect augments from all loaded modules
404 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
405 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
406 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
407 allAugments.addAll(inner.getValue().getAllAugments());
411 for (AugmentationSchemaBuilder augment : allAugments) {
412 setCorrectAugmentTargetPath(modules, augment);
416 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
417 final AugmentationSchemaBuilder augmentBuilder) {
418 ModuleBuilder module = ParserUtils.getParentModule(augmentBuilder);
419 SchemaPath oldSchemaPath = augmentBuilder.getTargetPath();
420 List<QName> oldPath = oldSchemaPath.getPath();
421 List<QName> newPath = new ArrayList<>();
422 for (QName qn : oldPath) {
423 ModuleBuilder currentModule = null;
424 String prefix = qn.getPrefix();
425 if (prefix == null || "".equals(prefix)) {
426 currentModule = module;
428 currentModule = ParserUtils.findDependentModuleBuilder(modules, module, prefix,
429 augmentBuilder.getLine());
431 QName newQName = new QName(currentModule.getNamespace(), currentModule.getRevision(), prefix,
433 newPath.add(newQName);
435 augmentBuilder.setTargetPath(new SchemaPath(newPath, augmentBuilder.getTargetPath().isAbsolute()));
439 * Go through all augment definitions and perform augmentation. It is
440 * expected that modules are already sorted by their dependencies.
445 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
446 // collect augments from all loaded modules
447 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
448 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
449 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
450 allAugments.addAll(inner.getValue().getAllAugments());
454 checkAugmentMandatoryNodes(allAugments);
456 for (int i = 0; i < allAugments.size(); i++) {
458 final AugmentationSchemaBuilder augment = allAugments.get(i);
459 // create collection of others
460 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
461 others.remove(augment);
464 boolean resolved = resolveAugment(modules, augment);
465 // while not resolved
467 while (!(resolved) && j < others.size()) {
468 // try to resolve next augment
469 resolveAugment(modules, others.get(j));
470 // then try to resolve first again
471 resolved = resolveAugment(modules, augment);
477 throw new YangParseException(augment.getModuleName(), augment.getLine(),
478 "Error in augment parsing: failed to find augment target");
484 * Check augments for mandatory nodes. If the target node is in another
485 * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
486 * If mandatory node is found, throw an exception.
491 private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
492 for (AugmentationSchemaBuilder augment : augments) {
493 String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
494 ModuleBuilder module = ParserUtils.getParentModule(augment);
495 String modulePrefix = module.getPrefix();
497 if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
501 for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
502 if (childNode.getConstraints().isMandatory()) {
503 throw new YangParseException(augment.getModuleName(), augment.getLine(),
504 "Error in augment parsing: cannot augment mandatory node");
511 * Search for augment target and perform augmentation.
517 * @return true if target node found, false otherwise
519 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
520 final AugmentationSchemaBuilder augment) {
521 if (augment.isResolved()) {
525 int line = augment.getLine();
526 ModuleBuilder module = getParentModule(augment);
527 List<QName> path = augment.getTargetPath().getPath();
528 Builder augmentParent = augment.getParent();
530 Builder firstNodeParent = null;
531 if (augmentParent instanceof ModuleBuilder) {
532 // if augment is defined under module, parent of first node is
534 final QName firstNameInPath = path.get(0);
535 String prefix = firstNameInPath.getPrefix();
536 if (prefix == null) {
537 prefix = module.getPrefix();
539 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
540 } else if (augmentParent instanceof UsesNodeBuilder) {
541 firstNodeParent = augmentParent.getParent();
543 // augment can be defined only under module or uses
544 throw new YangParseException(augment.getModuleName(), line,
545 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
548 return processAugmentation(augment, firstNodeParent, path);
552 * Go through all augment definitions and resolve them. This method works in
553 * same way as {@link #resolveAugments(Map)} except that if target node is
554 * not found in loaded modules, it search for target node in given context.
559 * SchemaContext containing already resolved modules
561 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
562 final SchemaContext context) {
563 // collect augments from all loaded modules
564 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
565 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
566 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
567 allAugments.addAll(inner.getValue().getAllAugments());
571 for (int i = 0; i < allAugments.size(); i++) {
572 // pick augment from list
573 final AugmentationSchemaBuilder augment = allAugments.get(i);
575 boolean resolved = resolveAugmentWithContext(modules, augment, context);
576 // while not resolved
578 while (!(resolved) && j < allAugments.size()) {
579 // try to resolve next augment
580 resolveAugmentWithContext(modules, allAugments.get(j), context);
581 // then try to resolve first again
582 resolved = resolveAugmentWithContext(modules, augment, context);
587 throw new YangParseException(augment.getModuleName(), augment.getLine(),
588 "Error in augment parsing: failed to find augment target");
594 * Search for augment target and perform augmentation.
601 * SchemaContext containing already resolved modules
602 * @return true if target node found, false otherwise
604 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
605 final AugmentationSchemaBuilder augment, final SchemaContext context) {
606 if (augment.isResolved()) {
609 int line = augment.getLine();
610 ModuleBuilder module = getParentModule(augment);
611 List<QName> path = augment.getTargetPath().getPath();
612 final QName firstNameInPath = path.get(0);
613 String prefix = firstNameInPath.getPrefix();
614 if (prefix == null) {
615 prefix = module.getPrefix();
617 Builder augmentParent = augment.getParent();
618 Builder currentParent = null;
620 if (augmentParent instanceof ModuleBuilder) {
621 // if augment is defined under module, first parent is target module
622 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
623 } else if (augmentParent instanceof UsesNodeBuilder) {
624 currentParent = augmentParent.getParent();
626 // augment can be defined only under module or uses
627 throw new YangParseException(augment.getModuleName(), augment.getLine(),
628 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
631 if (currentParent == null) {
632 return processAugmentationOnContext(augment, path, module, prefix, context);
634 return processAugmentation(augment, currentParent, path);
639 * Go through identity statements defined in current module and resolve
640 * their 'base' statement if present.
645 * module being resolved
647 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
648 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
649 for (IdentitySchemaNodeBuilder identity : identities) {
650 final String baseIdentityName = identity.getBaseIdentityName();
651 if (baseIdentityName != null) {
652 String baseIdentityPrefix = null;
653 String baseIdentityLocalName = null;
654 if (baseIdentityName.contains(":")) {
655 final String[] splitted = baseIdentityName.split(":");
656 baseIdentityPrefix = splitted[0];
657 baseIdentityLocalName = splitted[1];
659 baseIdentityPrefix = module.getPrefix();
660 baseIdentityLocalName = baseIdentityName;
662 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
665 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
666 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
667 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
668 identity.setBaseIdentity(idBuilder);
676 * Go through identity statements defined in current module and resolve
677 * their 'base' statement. Method tries to find base identity in given
678 * modules. If base identity is not found, method will search it in context.
685 * SchemaContext containing already resolved modules
687 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
688 final ModuleBuilder module, final SchemaContext context) {
689 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
690 for (IdentitySchemaNodeBuilder identity : identities) {
691 final String baseIdentityName = identity.getBaseIdentityName();
692 if (baseIdentityName != null) {
693 String baseIdentityPrefix = null;
694 String baseIdentityLocalName = null;
695 if (baseIdentityName.contains(":")) {
696 final String[] splitted = baseIdentityName.split(":");
697 baseIdentityPrefix = splitted[0];
698 baseIdentityLocalName = splitted[1];
700 baseIdentityPrefix = module.getPrefix();
701 baseIdentityLocalName = baseIdentityName;
703 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
704 baseIdentityPrefix, identity.getLine());
706 if (dependentModuleBuilder == null) {
707 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
709 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
710 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
711 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
712 identity.setBaseIdentity(idNode);
716 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
718 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
719 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
720 identity.setBaseIdentity(idBuilder);
729 * Find and add reference of uses target grouping.
734 * SchemaContext containing already resolved modules or null if
735 * context is not available
737 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
738 final SchemaContext context) {
739 final List<UsesNodeBuilder> allUses = new ArrayList<>();
740 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
741 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
742 allUses.addAll(inner.getValue().getAllUsesNodes());
745 for (UsesNodeBuilder usesNode : allUses) {
746 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
747 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
749 if (targetGroupingBuilder == null) {
750 if (context == null) {
751 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
752 + usesNode.getGroupingPathAsString() + "' not found.");
754 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
756 usesNode.setGroupingDefinition(targetGroupingDefinition);
759 usesNode.setGrouping(targetGroupingBuilder);
765 * Copy data from uses target. Augmentations have to be resolved already.
769 * @param resolveWithContext
770 * boolean value which says whether
771 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
772 * collectUsesDataFromContext} should be used for processing of
773 * individual uses node.
775 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final boolean resolveWithContext) {
776 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
777 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
778 ModuleBuilder module = inner.getValue();
779 List<UsesNodeBuilder> usesNodes = null;
780 boolean dataCollected = module.isAllUsesDataCollected();
782 while (!dataCollected) {
783 usesNodes = new ArrayList<>(module.getAllUsesNodes());
784 for (UsesNodeBuilder usesNode : usesNodes) {
785 if (!usesNode.isDataCollected()) {
786 if (resolveWithContext && usesNode.getGroupingBuilder() == null) {
787 GroupingUtils.collectUsesDataFromContext(usesNode);
789 GroupingUtils.collectUsesData(usesNode);
793 dataCollected = module.isAllUsesDataCollected();
800 * Update uses parent and perform refinement.
804 * @param resolveWithContext
805 * boolean value which says whether
806 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
807 * collectUsesDataFromContext} should be used for processing of
808 * individual uses node.
810 private void resolvedUsesPostProcessing(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
811 final boolean resolveWithContext) {
812 // new loop is must because in collecting data process new uses could
814 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
815 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
816 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
817 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
821 for (UsesNodeBuilder usesNode : allModulesUses) {
822 GroupingUtils.updateUsesParent(usesNode);
823 GroupingUtils.performRefine(usesNode);
825 for (UsesNodeBuilder usesNode : allModulesUses) {
826 GroupingUtils.fixUsesNodesPath(usesNode);
829 if (!resolveWithContext) {
830 for (UsesNodeBuilder usesNode : allModulesUses) {
831 if (usesNode.isCopy()) {
832 usesNode.getParent().getUsesNodes().remove(usesNode);
838 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
839 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
840 QName nodeType = usnb.getNodeType();
842 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
844 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
845 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
846 usnb.setNodeType(extension.getQName());
847 usnb.setExtensionBuilder(extension);
851 } catch (YangParseException e) {
852 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
853 + ": no such extension definition found.", e);
858 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
859 final ModuleBuilder module, final SchemaContext context) {
860 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
861 QName nodeType = usnb.getNodeType();
863 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
864 nodeType.getPrefix(), usnb.getLine());
866 if (dependentModuleBuilder == null) {
867 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
869 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
870 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
871 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
872 nodeType.getPrefix(), e.getQName().getLocalName()));
873 usnb.setExtensionDefinition(e);
878 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
879 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
880 usnb.setExtensionBuilder(extension);
886 } catch (YangParseException e) {
887 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
888 + ": no such extension definition found.", e);
895 * Traverse through modules and resolve their deviation statements.
900 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
901 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
902 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
903 ModuleBuilder b = inner.getValue();
904 resolveDeviation(modules, b);
910 * Traverse through module and resolve its deviation statements.
915 * module in which resolve deviations
917 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
918 for (DeviationBuilder dev : module.getDeviations()) {
919 int line = dev.getLine();
920 SchemaPath targetPath = dev.getTargetPath();
921 List<QName> path = targetPath.getPath();
922 QName q0 = path.get(0);
923 String prefix = q0.getPrefix();
924 if (prefix == null) {
925 prefix = module.getPrefix();
928 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
929 processDeviation(dev, dependentModuleBuilder, path, module);
934 * Traverse through modules and resolve their deviation statements with
940 * already resolved context
942 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
943 final SchemaContext context) {
944 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
945 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
946 ModuleBuilder b = inner.getValue();
947 resolveDeviationWithContext(modules, b, context);
953 * Traverse through module and resolve its deviation statements with given
959 * module in which resolve deviations
961 * already resolved context
963 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
964 final ModuleBuilder module, final SchemaContext context) {
965 for (DeviationBuilder dev : module.getDeviations()) {
966 int line = dev.getLine();
967 SchemaPath targetPath = dev.getTargetPath();
968 List<QName> path = targetPath.getPath();
969 QName q0 = path.get(0);
970 String prefix = q0.getPrefix();
971 if (prefix == null) {
972 prefix = module.getPrefix();
976 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
977 if (dependentModuleBuilder == null) {
978 Module dependentModule = findModuleFromContext(context, module, prefix, line);
979 Object currentParent = dependentModule;
981 for (int i = 0; i < path.size(); i++) {
982 if (currentParent == null) {
983 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
985 QName q = path.get(i);
986 name = q.getLocalName();
987 if (currentParent instanceof DataNodeContainer) {
988 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
992 if (currentParent == null) {
993 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
995 if (currentParent instanceof SchemaNode) {
996 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1000 processDeviation(dev, dependentModuleBuilder, path, module);
1006 * Correct deviation target path in deviation builder.
1010 * @param dependentModuleBuilder
1011 * module containing deviation target
1013 * current deviation target path
1017 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1018 final List<QName> path, final ModuleBuilder module) {
1019 final int line = dev.getLine();
1020 Builder currentParent = dependentModuleBuilder;
1022 for (int i = 0; i < path.size(); i++) {
1023 if (currentParent == null) {
1024 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1026 QName q = path.get(i);
1027 String name = q.getLocalName();
1028 if (currentParent instanceof DataNodeContainerBuilder) {
1029 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1033 if (!(currentParent instanceof SchemaNodeBuilder)) {
1034 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1036 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());