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.Collections;
20 import java.util.Date;
21 import java.util.HashMap;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedHashSet;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.TreeMap;
30 import org.antlr.v4.runtime.ANTLRInputStream;
31 import org.antlr.v4.runtime.CommonTokenStream;
32 import org.antlr.v4.runtime.tree.ParseTree;
33 import org.antlr.v4.runtime.tree.ParseTreeWalker;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
45 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
46 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
47 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
62 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
63 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
64 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
65 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
69 import com.google.common.collect.Lists;
70 import com.google.common.collect.Maps;
71 import com.google.common.collect.Sets;
73 public final class YangParserImpl implements YangModelParser {
74 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
76 private static final String FAIL_DEVIATION_TARGET = "Failed to find deviation target.";
79 public Set<Module> parseYangModels(final List<File> yangFiles) {
80 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
84 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
85 if (yangFiles != null) {
86 final Map<InputStream, File> inputStreams = Maps.newHashMap();
88 for (final File yangFile : yangFiles) {
90 inputStreams.put(new FileInputStream(yangFile), yangFile);
91 } catch (FileNotFoundException e) {
92 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
96 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
98 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
99 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
101 for (InputStream is : inputStreams.keySet()) {
104 } catch (IOException e) {
105 LOG.debug("Failed to close stream.");
109 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
111 return Collections.emptySet();
115 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
116 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
120 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
121 if (yangModelStreams != null) {
122 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
123 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
124 yangModelStreams, builderToStreamMap, context);
125 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
127 return Collections.emptySet();
131 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
132 if (yangFiles != null) {
133 final Map<InputStream, File> inputStreams = Maps.newHashMap();
135 for (final File yangFile : yangFiles) {
137 inputStreams.put(new FileInputStream(yangFile), yangFile);
138 } catch (FileNotFoundException e) {
139 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
143 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
144 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
145 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
147 for (InputStream is : inputStreams.keySet()) {
150 } catch (IOException e) {
151 LOG.debug("Failed to close stream.");
155 Map<File, Module> retVal = Maps.newLinkedHashMap();
156 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
158 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
159 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
160 builderToModule.getValue());
165 return Collections.emptyMap();
169 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
170 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
172 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
174 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
175 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
177 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
178 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
184 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
185 return new SchemaContextImpl(modules);
188 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
189 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
191 final ParseTreeWalker walker = new ParseTreeWalker();
192 final List<ParseTree> trees = parseStreams(inputStreams);
193 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
196 new YangModelBasicValidator(walker).validate(trees);
198 YangParserListenerImpl yangModelParser = null;
199 for (int i = 0; i < trees.size(); i++) {
200 yangModelParser = new YangParserListenerImpl();
201 walker.walk(yangModelParser, trees.get(i));
202 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
204 // We expect the order of trees and streams has to be the same
205 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
206 builders[i] = moduleBuilder;
211 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
212 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
213 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
216 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
217 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
218 final SchemaContext context) {
219 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
221 // LinkedHashMap must be used to preserve order
222 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
224 // module dependency graph sorted
225 List<ModuleBuilder> sorted = null;
226 if (context == null) {
227 sorted = ModuleDependencySort.sort(builders);
229 sorted = ModuleDependencySort.sortWithContext(context, builders);
232 for (final ModuleBuilder builder : sorted) {
233 if (builder == null) {
236 final String builderName = builder.getName();
237 Date builderRevision = builder.getRevision();
238 if (builderRevision == null) {
239 builderRevision = new Date(0L);
241 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
242 if (builderByRevision == null) {
243 builderByRevision = new TreeMap<Date, ModuleBuilder>();
245 builderByRevision.put(builderRevision, builder);
246 modules.put(builderName, builderByRevision);
251 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
252 final List<ParseTree> trees = new ArrayList<ParseTree>();
253 for (InputStream yangStream : yangStreams) {
254 trees.add(parseStream(yangStream));
259 private ParseTree parseStream(final InputStream yangStream) {
260 ParseTree result = null;
262 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
263 final YangLexer lexer = new YangLexer(input);
264 final CommonTokenStream tokens = new CommonTokenStream(lexer);
265 final YangParser parser = new YangParser(tokens);
266 parser.removeErrorListeners();
267 parser.addErrorListener(new YangErrorListener());
269 result = parser.yang();
270 } catch (IOException e) {
271 LOG.warn("Exception while reading yang file: " + yangStream, e);
276 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
277 // fix unresolved nodes
278 resolveAugmentsTargetPath(modules);
279 resolveUsesTargetGrouping(modules, null);
280 resolveDirtyNodes(modules);
281 resolveAugments(modules);
282 resolveUses(modules, false);
283 resolvedUsesPostProcessing(modules, false);
284 resolveDeviations(modules);
287 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
288 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
289 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
290 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
291 final ModuleBuilder moduleBuilder = childEntry.getValue();
292 final Module module = moduleBuilder.build();
293 modulesByRevision.put(childEntry.getKey(), module);
294 result.put(moduleBuilder, module);
300 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
301 final SchemaContext context) {
302 // fix unresolved nodes
304 // fixAugmentsTargetPath(modules);
305 resolveUsesTargetGrouping(modules, context);
306 resolvedDirtyNodesWithContext(modules, context);
307 resolveAugmentsWithContext(modules, context);
308 resolveUses(modules, true);
309 resolveDeviationsWithContext(modules, context);
312 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
313 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
314 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
315 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
316 final ModuleBuilder moduleBuilder = childEntry.getValue();
317 final Module module = moduleBuilder.build();
318 modulesByRevision.put(childEntry.getKey(), module);
319 result.put(moduleBuilder, module);
325 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
326 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
327 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
328 final ModuleBuilder module = childEntry.getValue();
329 resolveDirtyNodes(modules, module);
330 resolveIdentities(modules, module);
331 resolveUnknownNodes(modules, module);
336 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
337 final SchemaContext context) {
338 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
339 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
340 final ModuleBuilder module = childEntry.getValue();
341 resolveDirtyNodesWithContext(modules, module, context);
342 resolveIdentitiesWithContext(modules, module, context);
343 resolveUnknownNodesWithContext(modules, module, context);
349 * Search for dirty nodes (node which contains UnknownType) and resolve
353 * all available modules
357 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
358 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
359 if (!dirtyNodes.isEmpty()) {
360 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
361 if (nodeToResolve instanceof UnionTypeBuilder) {
362 // special handling for union types
363 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
364 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
365 // special handling for identityref types
366 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
367 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
369 resolveType(nodeToResolve, modules, module);
375 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
376 final ModuleBuilder module, SchemaContext context) {
377 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
378 if (!dirtyNodes.isEmpty()) {
379 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
380 if (nodeToResolve instanceof UnionTypeBuilder) {
381 // special handling for union types
382 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
383 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
384 // special handling for identityref types
385 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
386 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
388 resolveTypeWithContext(nodeToResolve, modules, module, context);
395 * Correct augment target path.
400 private void resolveAugmentsTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
401 // collect augments from all loaded modules
402 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
403 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
404 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
405 allAugments.addAll(inner.getValue().getAllAugments());
409 for (AugmentationSchemaBuilder augment : allAugments) {
410 setCorrectAugmentTargetPath(modules, augment);
414 private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
415 final AugmentationSchemaBuilder augmentBuilder) {
416 ModuleBuilder module = ParserUtils.getParentModule(augmentBuilder);
417 SchemaPath oldSchemaPath = augmentBuilder.getTargetPath();
418 List<QName> oldPath = oldSchemaPath.getPath();
419 List<QName> newPath = new ArrayList<>();
420 for (QName qn : oldPath) {
421 ModuleBuilder currentModule = null;
422 String prefix = qn.getPrefix();
423 if (prefix == null || "".equals(prefix)) {
424 currentModule = module;
426 currentModule = ParserUtils.findDependentModuleBuilder(modules, module, prefix,
427 augmentBuilder.getLine());
429 QName newQName = new QName(currentModule.getNamespace(), currentModule.getRevision(), prefix,
431 newPath.add(newQName);
433 augmentBuilder.setTargetPath(new SchemaPath(newPath, augmentBuilder.getTargetPath().isAbsolute()));
437 * Go through all augment definitions and perform augmentation. It is
438 * expected that modules are already sorted by their dependencies.
443 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
444 // collect augments from all loaded modules
445 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
446 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
447 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
448 allAugments.addAll(inner.getValue().getAllAugments());
452 for (int i = 0; i < allAugments.size(); i++) {
454 final AugmentationSchemaBuilder augment = allAugments.get(i);
455 // create collection of others
456 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
457 others.remove(augment);
460 boolean resolved = resolveAugment(modules, augment);
461 // while not resolved
463 while (!(resolved) && j < others.size()) {
464 // try to resolve next augment
465 resolveAugment(modules, others.get(j));
466 // then try to resolve first again
467 resolved = resolveAugment(modules, augment);
473 throw new YangParseException(augment.getModuleName(), augment.getLine(),
474 "Error in augment parsing: failed to find augment target");
480 * Search for augment target and perform augmentation.
486 * @return true if target node found, false otherwise
488 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
489 final AugmentationSchemaBuilder augment) {
490 if (augment.isResolved()) {
494 int line = augment.getLine();
495 ModuleBuilder module = getParentModule(augment);
496 List<QName> path = augment.getTargetPath().getPath();
497 Builder augmentParent = augment.getParent();
499 Builder firstNodeParent = null;
500 if (augmentParent instanceof ModuleBuilder) {
501 // if augment is defined under module, parent of first node is
503 final QName firstNameInPath = path.get(0);
504 String prefix = firstNameInPath.getPrefix();
505 if (prefix == null) {
506 prefix = module.getPrefix();
508 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
509 } else if (augmentParent instanceof UsesNodeBuilder) {
510 firstNodeParent = augmentParent.getParent();
512 // augment can be defined only under module or uses
513 throw new YangParseException(augment.getModuleName(), line,
514 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
517 return processAugmentation(augment, firstNodeParent, path);
521 * Go through all augment definitions and resolve them. This method works in
522 * same way as {@link #resolveAugments(Map)} except that if target node is
523 * not found in loaded modules, it search for target node in given context.
528 * SchemaContext containing already resolved modules
530 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
531 final SchemaContext context) {
532 // collect augments from all loaded modules
533 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
534 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
535 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
536 allAugments.addAll(inner.getValue().getAllAugments());
540 for (int i = 0; i < allAugments.size(); i++) {
541 // pick augment from list
542 final AugmentationSchemaBuilder augment = allAugments.get(i);
544 boolean resolved = resolveAugmentWithContext(modules, augment, context);
545 // while not resolved
547 while (!(resolved) && j < allAugments.size()) {
548 // try to resolve next augment
549 resolveAugmentWithContext(modules, allAugments.get(j), context);
550 // then try to resolve first again
551 resolved = resolveAugmentWithContext(modules, augment, context);
556 throw new YangParseException(augment.getModuleName(), augment.getLine(),
557 "Error in augment parsing: failed to find augment target");
563 * Search for augment target and perform augmentation.
570 * SchemaContext containing already resolved modules
571 * @return true if target node found, false otherwise
573 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
574 final AugmentationSchemaBuilder augment, final SchemaContext context) {
575 if (augment.isResolved()) {
578 int line = augment.getLine();
579 ModuleBuilder module = getParentModule(augment);
580 List<QName> path = augment.getTargetPath().getPath();
581 final QName firstNameInPath = path.get(0);
582 String prefix = firstNameInPath.getPrefix();
583 if (prefix == null) {
584 prefix = module.getPrefix();
586 Builder augmentParent = augment.getParent();
587 Builder currentParent = null;
589 if (augmentParent instanceof ModuleBuilder) {
590 // if augment is defined under module, first parent is target module
591 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
592 } else if (augmentParent instanceof UsesNodeBuilder) {
593 currentParent = augmentParent.getParent();
595 // augment can be defined only under module or uses
596 throw new YangParseException(augment.getModuleName(), augment.getLine(),
597 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
600 if (currentParent == null) {
601 return processAugmentationOnContext(augment, path, module, prefix, context);
603 return processAugmentation(augment, currentParent, path);
608 * Go through identity statements defined in current module and resolve
609 * their 'base' statement if present.
614 * module being resolved
616 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
617 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
618 for (IdentitySchemaNodeBuilder identity : identities) {
619 final String baseIdentityName = identity.getBaseIdentityName();
620 if (baseIdentityName != null) {
621 String baseIdentityPrefix = null;
622 String baseIdentityLocalName = null;
623 if (baseIdentityName.contains(":")) {
624 final String[] splitted = baseIdentityName.split(":");
625 baseIdentityPrefix = splitted[0];
626 baseIdentityLocalName = splitted[1];
628 baseIdentityPrefix = module.getPrefix();
629 baseIdentityLocalName = baseIdentityName;
631 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
634 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
635 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
636 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
637 identity.setBaseIdentity(idBuilder);
645 * Go through identity statements defined in current module and resolve
646 * their 'base' statement. Method tries to find base identity in given
647 * modules. If base identity is not found, method will search it in context.
654 * SchemaContext containing already resolved modules
656 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
657 final ModuleBuilder module, final SchemaContext context) {
658 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
659 for (IdentitySchemaNodeBuilder identity : identities) {
660 final String baseIdentityName = identity.getBaseIdentityName();
661 if (baseIdentityName != null) {
662 String baseIdentityPrefix = null;
663 String baseIdentityLocalName = null;
664 if (baseIdentityName.contains(":")) {
665 final String[] splitted = baseIdentityName.split(":");
666 baseIdentityPrefix = splitted[0];
667 baseIdentityLocalName = splitted[1];
669 baseIdentityPrefix = module.getPrefix();
670 baseIdentityLocalName = baseIdentityName;
672 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
673 baseIdentityPrefix, identity.getLine());
675 if (dependentModuleBuilder == null) {
676 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
678 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
679 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
680 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
681 identity.setBaseIdentity(idNode);
685 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
687 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
688 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
689 identity.setBaseIdentity(idBuilder);
698 * Find and add reference of uses target grouping.
703 * SchemaContext containing already resolved modules or null if
704 * context is not available
706 private void resolveUsesTargetGrouping(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
707 final SchemaContext context) {
708 final List<UsesNodeBuilder> allUses = new ArrayList<>();
709 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
710 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
711 allUses.addAll(inner.getValue().getAllUsesNodes());
714 for (UsesNodeBuilder usesNode : allUses) {
715 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
716 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
718 if (targetGroupingBuilder == null) {
719 if (context == null) {
720 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
721 + usesNode.getGroupingPathAsString() + "' not found.");
723 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
725 usesNode.setGroupingDefinition(targetGroupingDefinition);
728 usesNode.setGrouping(targetGroupingBuilder);
734 * Copy data from uses target. Augmentations have to be resolved already.
738 * @param resolveWithContext
739 * boolean value which says whether
740 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
741 * collectUsesDataFromContext} should be used for processing of
742 * individual uses node.
744 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final boolean resolveWithContext) {
745 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
746 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
747 ModuleBuilder module = inner.getValue();
748 List<UsesNodeBuilder> usesNodes = null;
749 boolean dataCollected = module.isAllUsesDataCollected();
751 while (!dataCollected) {
752 usesNodes = new ArrayList<>(module.getAllUsesNodes());
753 for (UsesNodeBuilder usesNode : usesNodes) {
754 if (!usesNode.isDataCollected()) {
755 if (resolveWithContext && usesNode.getGroupingBuilder() == null) {
756 GroupingUtils.collectUsesDataFromContext(usesNode);
758 GroupingUtils.collectUsesData(usesNode);
762 dataCollected = module.isAllUsesDataCollected();
769 * Update uses parent and perform refinement.
773 * @param resolveWithContext
774 * boolean value which says whether
775 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
776 * collectUsesDataFromContext} should be used for processing of
777 * individual uses node.
779 private void resolvedUsesPostProcessing(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
780 final boolean resolveWithContext) {
781 // new loop is must because in collecting data process new uses could
783 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
784 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
785 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
786 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
790 for (UsesNodeBuilder usesNode : allModulesUses) {
791 GroupingUtils.updateUsesParent(usesNode);
792 GroupingUtils.performRefine(usesNode);
794 for (UsesNodeBuilder usesNode : allModulesUses) {
795 GroupingUtils.fixUsesNodesPath(usesNode);
798 if (!resolveWithContext) {
799 for (UsesNodeBuilder usesNode : allModulesUses) {
800 if (usesNode.isCopy()) {
801 usesNode.getParent().getUsesNodes().remove(usesNode);
807 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
808 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
809 QName nodeType = usnb.getNodeType();
811 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
813 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
814 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
815 usnb.setNodeType(extension.getQName());
816 usnb.setExtensionBuilder(extension);
820 } catch (YangParseException e) {
821 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
822 + ": no such extension definition found.", e);
827 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
828 final ModuleBuilder module, final SchemaContext context) {
829 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
830 QName nodeType = usnb.getNodeType();
832 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
833 nodeType.getPrefix(), usnb.getLine());
835 if (dependentModuleBuilder == null) {
836 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
838 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
839 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
840 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
841 nodeType.getPrefix(), e.getQName().getLocalName()));
842 usnb.setExtensionDefinition(e);
847 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
848 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
849 usnb.setExtensionBuilder(extension);
855 } catch (YangParseException e) {
856 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
857 + ": no such extension definition found.", e);
864 * Traverse through modules and resolve their deviation statements.
869 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
870 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
871 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
872 ModuleBuilder b = inner.getValue();
873 resolveDeviation(modules, b);
879 * Traverse through module and resolve its deviation statements.
884 * module in which resolve deviations
886 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
887 for (DeviationBuilder dev : module.getDeviations()) {
888 int line = dev.getLine();
889 SchemaPath targetPath = dev.getTargetPath();
890 List<QName> path = targetPath.getPath();
891 QName q0 = path.get(0);
892 String prefix = q0.getPrefix();
893 if (prefix == null) {
894 prefix = module.getPrefix();
897 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
898 processDeviation(dev, dependentModuleBuilder, path, module);
903 * Traverse through modules and resolve their deviation statements with
909 * already resolved context
911 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
912 final SchemaContext context) {
913 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
914 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
915 ModuleBuilder b = inner.getValue();
916 resolveDeviationWithContext(modules, b, context);
922 * Traverse through module and resolve its deviation statements with given
928 * module in which resolve deviations
930 * already resolved context
932 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
933 final ModuleBuilder module, final SchemaContext context) {
934 for (DeviationBuilder dev : module.getDeviations()) {
935 int line = dev.getLine();
936 SchemaPath targetPath = dev.getTargetPath();
937 List<QName> path = targetPath.getPath();
938 QName q0 = path.get(0);
939 String prefix = q0.getPrefix();
940 if (prefix == null) {
941 prefix = module.getPrefix();
945 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
946 if (dependentModuleBuilder == null) {
947 Module dependentModule = findModuleFromContext(context, module, prefix, line);
948 Object currentParent = dependentModule;
950 for (int i = 0; i < path.size(); i++) {
951 if (currentParent == null) {
952 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
954 QName q = path.get(i);
955 name = q.getLocalName();
956 if (currentParent instanceof DataNodeContainer) {
957 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
961 if (currentParent == null) {
962 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
964 if (currentParent instanceof SchemaNode) {
965 dev.setTargetPath(((SchemaNode) currentParent).getPath());
969 processDeviation(dev, dependentModuleBuilder, path, module);
975 * Correct deviation target path in deviation builder.
979 * @param dependentModuleBuilder
980 * module containing deviation target
982 * current deviation target path
986 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
987 final List<QName> path, final ModuleBuilder module) {
988 final int line = dev.getLine();
989 Builder currentParent = dependentModuleBuilder;
991 for (int i = 0; i < path.size(); i++) {
992 if (currentParent == null) {
993 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
995 QName q = path.get(i);
996 String name = q.getLocalName();
997 if (currentParent instanceof DataNodeContainerBuilder) {
998 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1002 if (!(currentParent instanceof SchemaNodeBuilder)) {
1003 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
1005 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());