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 com.google.common.base.Preconditions;
33 import org.antlr.v4.runtime.ANTLRInputStream;
34 import org.antlr.v4.runtime.CommonTokenStream;
35 import org.antlr.v4.runtime.tree.ParseTree;
36 import org.antlr.v4.runtime.tree.ParseTreeWalker;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
41 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
42 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
43 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.Module;
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.model.util.IdentityrefType;
50 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
65 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
66 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
67 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
68 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
69 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
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 final List<File> modules = new ArrayList<>();
93 for (String fileName : fileList) {
94 if (fileName.equals(yangFileName)) {
97 modules.add(new File(directory, fileName));
99 modules.add(yangFile);
101 return parseYangModels(modules);
105 public Set<Module> parseYangModels(final List<File> yangFiles) {
106 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
110 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
111 if (yangFiles != null) {
112 final Map<InputStream, File> inputStreams = Maps.newHashMap();
114 for (final File yangFile : yangFiles) {
116 inputStreams.put(new FileInputStream(yangFile), yangFile);
117 } catch (FileNotFoundException e) {
118 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
122 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
124 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
125 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
127 for (InputStream is : inputStreams.keySet()) {
130 } catch (IOException e) {
131 LOG.debug("Failed to close stream.");
135 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
137 return Collections.emptySet();
141 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
142 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
146 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
147 if (yangModelStreams != null) {
148 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
149 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
150 yangModelStreams, builderToStreamMap, context);
151 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
153 return Collections.emptySet();
157 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
158 if (yangFiles != null) {
159 final Map<InputStream, File> inputStreams = Maps.newHashMap();
161 for (final File yangFile : yangFiles) {
163 inputStreams.put(new FileInputStream(yangFile), yangFile);
164 } catch (FileNotFoundException e) {
165 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
169 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
170 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
171 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
173 for (InputStream is : inputStreams.keySet()) {
176 } catch (IOException e) {
177 LOG.debug("Failed to close stream.");
181 Map<File, Module> retVal = Maps.newLinkedHashMap();
182 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
184 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
185 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
186 builderToModule.getValue());
191 return Collections.emptyMap();
195 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
196 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
198 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
200 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
201 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
203 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
204 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
210 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
211 return new SchemaContextImpl(modules);
214 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
215 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
217 final ParseTreeWalker walker = new ParseTreeWalker();
218 final List<ParseTree> trees = parseStreams(inputStreams);
219 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
222 new YangModelBasicValidator(walker).validate(trees);
224 YangParserListenerImpl yangModelParser;
225 for (int i = 0; i < trees.size(); i++) {
226 yangModelParser = new YangParserListenerImpl();
227 walker.walk(yangModelParser, trees.get(i));
228 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
230 // We expect the order of trees and streams has to be the same
231 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
232 builders[i] = moduleBuilder;
237 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
238 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
239 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
242 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
243 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
244 final SchemaContext context) {
245 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
247 // LinkedHashMap must be used to preserve order
248 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
250 // module dependency graph sorted
251 List<ModuleBuilder> sorted;
252 if (context == null) {
253 sorted = ModuleDependencySort.sort(builders);
255 sorted = ModuleDependencySort.sortWithContext(context, builders);
258 for (final ModuleBuilder builder : sorted) {
259 if (builder == null) {
262 final String builderName = builder.getName();
263 Date builderRevision = builder.getRevision();
264 if (builderRevision == null) {
265 builderRevision = new Date(0L);
267 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
268 if (builderByRevision == null) {
269 builderByRevision = new TreeMap<Date, ModuleBuilder>();
271 builderByRevision.put(builderRevision, builder);
272 modules.put(builderName, builderByRevision);
277 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
278 final List<ParseTree> trees = new ArrayList<ParseTree>();
279 for (InputStream yangStream : yangStreams) {
280 trees.add(parseStream(yangStream));
285 private ParseTree parseStream(final InputStream yangStream) {
286 ParseTree result = null;
288 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
289 final YangLexer lexer = new YangLexer(input);
290 final CommonTokenStream tokens = new CommonTokenStream(lexer);
291 final YangParser parser = new YangParser(tokens);
292 parser.removeErrorListeners();
293 parser.addErrorListener(new YangErrorListener());
295 result = parser.yang();
296 } catch (IOException e) {
297 LOG.warn("Exception while reading yang file: " + yangStream, e);
302 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
303 // fix unresolved nodes
304 resolveAugmentsTargetPath(modules, null);
305 resolveUsesTargetGrouping(modules, null);
306 resolveDirtyNodes(modules);
307 resolveAugments(modules);
308 resolveUses(modules, false);
309 resolvedUsesPostProcessing(modules, false);
310 resolveDeviations(modules);
313 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
314 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
315 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
316 final ModuleBuilder moduleBuilder = childEntry.getValue();
317 final Module module = moduleBuilder.build();
318 result.put(moduleBuilder, module);
324 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
325 final SchemaContext context) {
326 // fix unresolved nodes
327 resolveAugmentsTargetPath(modules, context);
328 resolveUsesTargetGrouping(modules, context);
329 resolvedDirtyNodesWithContext(modules, context);
330 resolveAugmentsWithContext(modules, context);
331 resolveUses(modules, true);
332 resolvedUsesPostProcessing(modules, true);
333 resolveDeviationsWithContext(modules, context);
336 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
337 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
338 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
339 final ModuleBuilder moduleBuilder = childEntry.getValue();
340 final Module module = moduleBuilder.build();
341 result.put(moduleBuilder, module);
347 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
348 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
349 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
350 final ModuleBuilder module = childEntry.getValue();
351 resolveDirtyNodes(modules, module);
352 resolveIdentities(modules, module);
353 resolveUnknownNodes(modules, module);
358 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
359 final SchemaContext context) {
360 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
361 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
362 final ModuleBuilder module = childEntry.getValue();
363 resolveDirtyNodesWithContext(modules, module, context);
364 resolveIdentitiesWithContext(modules, module, context);
365 resolveUnknownNodesWithContext(modules, module, context);
371 * Search for dirty nodes (node which contains UnknownType) and resolve
375 * all available modules
379 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
380 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
381 if (!dirtyNodes.isEmpty()) {
382 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
383 if (nodeToResolve instanceof UnionTypeBuilder) {
384 // special handling for union types
385 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
386 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
387 // special handling for identityref types
388 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
389 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
391 resolveType(nodeToResolve, modules, module);
397 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
398 final ModuleBuilder module, SchemaContext context) {
399 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
400 if (!dirtyNodes.isEmpty()) {
401 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
402 if (nodeToResolve instanceof UnionTypeBuilder) {
403 // special handling for union types
404 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
405 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
406 // special handling for identityref types
407 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
408 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
410 resolveTypeWithContext(nodeToResolve, modules, module, context);
417 * Correct augment target path.
422 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
423 SchemaContext context) {
424 // collect augments from all loaded modules
425 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
426 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
427 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
428 allAugments.addAll(inner.getValue().getAllAugments());
432 for (AugmentationSchemaBuilder augment : allAugments) {
433 setCorrectAugmentTargetPath(modules, augment, context);
437 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
438 final AugmentationSchemaBuilder augment, final SchemaContext context) {
439 ModuleBuilder module = ParserUtils.getParentModule(augment);
440 SchemaPath oldSchemaPath = augment.getTargetPath();
441 List<QName> oldPath = oldSchemaPath.getPath();
442 List<QName> newPath = new ArrayList<>();
443 for (QName qn : oldPath) {
444 URI ns = module.getNamespace();
445 Date rev = module.getRevision();
446 String pref = module.getPrefix();
447 String localPrefix = qn.getPrefix();
448 if (localPrefix != null && !("".equals(localPrefix))) {
449 ModuleBuilder currentModule = ParserUtils.findModuleFromBuilders(modules, module, localPrefix,
451 if (currentModule == null) {
452 Module m = ParserUtils.findModuleFromContext(context, module, localPrefix, augment.getLine());
454 throw new YangParseException(module.getName(), augment.getLine(), "Module with prefix "
455 + localPrefix + " not found.");
457 ns = m.getNamespace();
458 rev = m.getRevision();
459 pref = m.getPrefix();
461 ns = currentModule.getNamespace();
462 rev = currentModule.getRevision();
463 pref = currentModule.getPrefix();
466 newPath.add(new QName(ns, rev, pref, qn.getLocalName()));
468 augment.setTargetNodeSchemaPath(new SchemaPath(newPath, augment.getTargetPath().isAbsolute()));
472 * Go through all augment definitions and perform augmentation. It is
473 * expected that modules are already sorted by their dependencies.
478 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
479 // collect augments from all loaded modules
480 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
481 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
482 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
483 allAugments.addAll(inner.getValue().getAllAugments());
487 checkAugmentMandatoryNodes(allAugments);
489 for (int i = 0; i < allAugments.size(); i++) {
491 final AugmentationSchemaBuilder augment = allAugments.get(i);
492 // create collection of others
493 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
494 others.remove(augment);
497 boolean resolved = resolveAugment(modules, augment);
498 // while not resolved
500 while (!(resolved) && j < others.size()) {
501 // try to resolve next augment
502 resolveAugment(modules, others.get(j));
503 // then try to resolve first again
504 resolved = resolveAugment(modules, augment);
510 throw new YangParseException(augment.getModuleName(), augment.getLine(),
511 "Error in augment parsing: failed to find augment target");
517 * Check augments for mandatory nodes. If the target node is in another
518 * module, then nodes added by the augmentation MUST NOT be mandatory nodes.
519 * If mandatory node is found, throw an exception.
524 private void checkAugmentMandatoryNodes(Collection<AugmentationSchemaBuilder> augments) {
525 for (AugmentationSchemaBuilder augment : augments) {
526 String augmentPrefix = augment.getTargetPath().getPath().get(0).getPrefix();
527 ModuleBuilder module = ParserUtils.getParentModule(augment);
528 String modulePrefix = module.getPrefix();
530 if (augmentPrefix == null || augmentPrefix.isEmpty() || augmentPrefix.equals(modulePrefix)) {
534 for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
535 if (childNode.getConstraints().isMandatory()) {
536 throw new YangParseException(augment.getModuleName(), augment.getLine(),
537 "Error in augment parsing: cannot augment mandatory node");
544 * Search for augment target and perform augmentation.
550 * @return true if target node found, false otherwise
552 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
553 final AugmentationSchemaBuilder augment) {
554 if (augment.isResolved()) {
558 int line = augment.getLine();
559 ModuleBuilder module = getParentModule(augment);
560 List<QName> path = augment.getTargetPath().getPath();
561 Builder augmentParent = augment.getParent();
563 Builder firstNodeParent;
564 if (augmentParent instanceof ModuleBuilder) {
565 // if augment is defined under module, parent of first node is
567 final QName firstNameInPath = path.get(0);
568 String prefix = firstNameInPath.getPrefix();
569 if (prefix == null) {
570 prefix = module.getPrefix();
572 firstNodeParent = findModuleFromBuilders(modules, module, prefix, line);
573 } else if (augmentParent instanceof UsesNodeBuilder) {
574 firstNodeParent = augmentParent.getParent();
576 // augment can be defined only under module or uses
577 throw new YangParseException(augment.getModuleName(), line,
578 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
581 return processAugmentation(augment, firstNodeParent, path);
585 * Go through all augment definitions and resolve them. This method works in
586 * same way as {@link #resolveAugments(Map)} except that if target node is
587 * not found in loaded modules, it search for target node in given context.
592 * SchemaContext containing already resolved modules
594 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
595 final SchemaContext context) {
596 // collect augments from all loaded modules
597 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
598 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
599 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
600 allAugments.addAll(inner.getValue().getAllAugments());
604 for (int i = 0; i < allAugments.size(); i++) {
605 // pick augment from list
606 final AugmentationSchemaBuilder augment = allAugments.get(i);
608 boolean resolved = resolveAugmentWithContext(modules, augment, context);
609 // while not resolved
611 while (!(resolved) && j < allAugments.size()) {
612 // try to resolve next augment
613 resolveAugmentWithContext(modules, allAugments.get(j), context);
614 // then try to resolve first again
615 resolved = resolveAugmentWithContext(modules, augment, context);
620 throw new YangParseException(augment.getModuleName(), augment.getLine(),
621 "Error in augment parsing: failed to find augment target");
627 * Search for augment target and perform augmentation.
634 * SchemaContext containing already resolved modules
635 * @return true if target node found, false otherwise
637 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
638 final AugmentationSchemaBuilder augment, final SchemaContext context) {
639 if (augment.isResolved()) {
642 int line = augment.getLine();
643 ModuleBuilder module = getParentModule(augment);
644 List<QName> path = augment.getTargetNodeSchemaPath().getPath();
645 final QName firstNameInPath = path.get(0);
646 String prefix = firstNameInPath.getPrefix();
647 if (prefix == null) {
648 prefix = module.getPrefix();
650 Builder augmentParent = augment.getParent();
651 Builder currentParent;
652 if (augmentParent instanceof ModuleBuilder) {
653 // if augment is defined under module, first parent is target module
654 currentParent = findModuleFromBuilders(modules, module, prefix, line);
655 } else if (augmentParent instanceof UsesNodeBuilder) {
656 currentParent = augmentParent.getParent();
658 // augment can be defined only under module or uses
659 throw new YangParseException(augment.getModuleName(), augment.getLine(),
660 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
663 if (currentParent == null) {
664 return processAugmentationOnContext(augment, path, module, prefix, context);
666 return processAugmentation(augment, currentParent, path);
671 * Go through identity statements defined in current module and resolve
672 * their 'base' statement if present.
677 * module being resolved
679 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
680 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
681 for (IdentitySchemaNodeBuilder identity : identities) {
682 final String baseIdentityName = identity.getBaseIdentityName();
683 if (baseIdentityName != null) {
684 String baseIdentityPrefix;
685 String baseIdentityLocalName;
686 if (baseIdentityName.contains(":")) {
687 final String[] splitted = baseIdentityName.split(":");
688 baseIdentityPrefix = splitted[0];
689 baseIdentityLocalName = splitted[1];
691 baseIdentityPrefix = module.getPrefix();
692 baseIdentityLocalName = baseIdentityName;
694 final ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, baseIdentityPrefix,
697 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
698 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
699 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
700 identity.setBaseIdentity(idBuilder);
708 * Go through identity statements defined in current module and resolve
709 * their 'base' statement. Method tries to find base identity in given
710 * modules. If base identity is not found, method will search it in context.
717 * SchemaContext containing already resolved modules
719 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
720 final ModuleBuilder module, final SchemaContext context) {
721 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
722 for (IdentitySchemaNodeBuilder identity : identities) {
723 final String baseIdentityName = identity.getBaseIdentityName();
724 if (baseIdentityName != null) {
725 String baseIdentityPrefix;
726 String baseIdentityLocalName;
727 if (baseIdentityName.contains(":")) {
728 final String[] splitted = baseIdentityName.split(":");
729 baseIdentityPrefix = splitted[0];
730 baseIdentityLocalName = splitted[1];
732 baseIdentityPrefix = module.getPrefix();
733 baseIdentityLocalName = baseIdentityName;
735 final ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
736 baseIdentityPrefix, identity.getLine());
738 if (dependentModuleBuilder == null) {
739 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
741 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
742 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
743 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
744 identity.setBaseIdentity(idNode);
748 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
750 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
751 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
752 identity.setBaseIdentity(idBuilder);
761 * Find and add reference of uses target grouping.
766 * SchemaContext containing already resolved modules or null if
767 * context is not available
769 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
770 final SchemaContext context) {
771 final List<UsesNodeBuilder> allUses = new ArrayList<>();
772 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
773 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
774 allUses.addAll(inner.getValue().getAllUsesNodes());
777 for (UsesNodeBuilder usesNode : allUses) {
778 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
779 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
781 if (targetGroupingBuilder == null) {
782 if (context == null) {
783 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
784 + usesNode.getGroupingPathAsString() + "' not found.");
786 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
788 usesNode.setGroupingDefinition(targetGroupingDefinition);
791 usesNode.setGrouping(targetGroupingBuilder);
797 * Copy data from uses target. Augmentations have to be resolved already.
801 * @param resolveWithContext
802 * boolean value which says whether
803 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
804 * collectUsesDataFromContext} should be used for processing of
805 * individual uses node.
807 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final boolean resolveWithContext) {
808 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
809 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
810 ModuleBuilder module = inner.getValue();
811 boolean dataCollected = module.isAllUsesDataCollected();
813 List<UsesNodeBuilder> usesNodes;
814 while (!dataCollected) {
815 usesNodes = new ArrayList<>(module.getAllUsesNodes());
816 for (UsesNodeBuilder usesNode : usesNodes) {
817 if (!usesNode.isDataCollected()) {
818 if (resolveWithContext && usesNode.getGroupingBuilder() == null) {
819 GroupingUtils.collectUsesDataFromContext(usesNode);
821 GroupingUtils.collectUsesData(usesNode);
825 dataCollected = module.isAllUsesDataCollected();
832 * Update uses parent and perform refinement.
836 * @param resolveWithContext
837 * boolean value which says whether
838 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
839 * collectUsesDataFromContext} should be used for processing of
840 * individual uses node.
842 private void resolvedUsesPostProcessing(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
843 final boolean resolveWithContext) {
844 // new loop is must because in collecting data process new uses could
846 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
847 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
848 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
849 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
853 for (UsesNodeBuilder usesNode : allModulesUses) {
854 GroupingUtils.updateUsesParent(usesNode);
855 GroupingUtils.performRefine(usesNode);
858 if (!resolveWithContext) {
859 for (UsesNodeBuilder usesNode : allModulesUses) {
860 if (usesNode.isCopy()) {
861 usesNode.getParent().getUsesNodes().remove(usesNode);
867 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
868 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
869 QName nodeType = usnb.getNodeType();
871 ModuleBuilder dependentModule = findModuleFromBuilders(modules, module, nodeType.getPrefix(),
873 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
874 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
875 usnb.setNodeType(extension.getQName());
876 usnb.setExtensionBuilder(extension);
880 } catch (YangParseException e) {
881 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
882 + ": no such extension definition found.", e);
887 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
888 final ModuleBuilder module, final SchemaContext context) {
889 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
890 QName nodeType = usnb.getNodeType();
892 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module,
893 nodeType.getPrefix(), usnb.getLine());
895 if (dependentModuleBuilder == null) {
896 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
898 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
899 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
900 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
901 nodeType.getPrefix(), e.getQName().getLocalName()));
902 usnb.setExtensionDefinition(e);
907 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
908 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
909 usnb.setExtensionBuilder(extension);
915 } catch (YangParseException e) {
916 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
917 + ": no such extension definition found.", e);
924 * Traverse through modules and resolve their deviation statements.
929 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
930 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
931 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
932 ModuleBuilder b = inner.getValue();
933 resolveDeviation(modules, b);
939 * Traverse through module and resolve its deviation statements.
944 * module in which resolve deviations
946 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
947 for (DeviationBuilder dev : module.getDeviations()) {
948 int line = dev.getLine();
949 SchemaPath targetPath = dev.getTargetPath();
950 List<QName> path = targetPath.getPath();
951 QName q0 = path.get(0);
952 String prefix = q0.getPrefix();
953 if (prefix == null) {
954 prefix = module.getPrefix();
957 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
958 processDeviation(dev, dependentModuleBuilder, path, module);
963 * Traverse through modules and resolve their deviation statements with
969 * already resolved context
971 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
972 final SchemaContext context) {
973 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
974 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
975 ModuleBuilder b = inner.getValue();
976 resolveDeviationWithContext(modules, b, context);
982 * Traverse through module and resolve its deviation statements with given
988 * module in which resolve deviations
990 * already resolved context
992 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
993 final ModuleBuilder module, final SchemaContext context) {
994 for (DeviationBuilder dev : module.getDeviations()) {
995 int line = dev.getLine();
996 SchemaPath targetPath = dev.getTargetPath();
997 List<QName> path = targetPath.getPath();
998 QName q0 = path.get(0);
999 String prefix = q0.getPrefix();
1000 if (prefix == null) {
1001 prefix = module.getPrefix();
1005 ModuleBuilder dependentModuleBuilder = findModuleFromBuilders(modules, module, prefix, line);
1006 if (dependentModuleBuilder == null) {
1007 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1008 Object currentParent = dependentModule;
1010 for (QName q : path) {
1011 if (currentParent == null) {
1012 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1014 name = q.getLocalName();
1015 if (currentParent instanceof DataNodeContainer) {
1016 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1020 if (currentParent == null) {
1021 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1023 if (currentParent instanceof SchemaNode) {
1024 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1028 processDeviation(dev, dependentModuleBuilder, path, module);
1034 * Correct deviation target path in deviation builder.
1038 * @param dependentModuleBuilder
1039 * module containing deviation target
1041 * current deviation target path
1045 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1046 final List<QName> path, final ModuleBuilder module) {
1047 final int line = dev.getLine();
1048 Builder currentParent = dependentModuleBuilder;
1050 for (QName q : path) {
1051 if (currentParent == null) {
1052 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1054 String name = q.getLocalName();
1055 if (currentParent instanceof DataNodeContainerBuilder) {
1056 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1060 if (!(currentParent instanceof SchemaNodeBuilder)) {
1061 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1063 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());