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 findUsesTargets(modules, null);
279 resolveDirtyNodes(modules);
280 resolveAugments(modules);
281 resolveUses(modules, false);
282 resolveDeviations(modules);
285 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
286 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
287 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
288 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
289 final ModuleBuilder moduleBuilder = childEntry.getValue();
290 final Module module = moduleBuilder.build();
291 modulesByRevision.put(childEntry.getKey(), module);
292 result.put(moduleBuilder, module);
298 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
299 final SchemaContext context) {
300 // fix unresolved nodes
301 findUsesTargets(modules, context);
302 resolvedDirtyNodesWithContext(modules, context);
303 resolveAugmentsWithContext(modules, context);
304 resolveUses(modules, true);
305 resolveDeviationsWithContext(modules, context);
308 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
309 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
310 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
311 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
312 final ModuleBuilder moduleBuilder = childEntry.getValue();
313 final Module module = moduleBuilder.build();
314 modulesByRevision.put(childEntry.getKey(), module);
315 result.put(moduleBuilder, module);
321 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
322 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
323 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
324 final ModuleBuilder module = childEntry.getValue();
325 resolveDirtyNodes(modules, module);
326 resolveIdentities(modules, module);
327 resolveUnknownNodes(modules, module);
332 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
333 final SchemaContext context) {
334 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
335 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
336 final ModuleBuilder module = childEntry.getValue();
337 resolveDirtyNodesWithContext(modules, module, context);
338 resolveIdentitiesWithContext(modules, module, context);
339 resolveUnknownNodesWithContext(modules, module, context);
345 * Search for dirty nodes (node which contains UnknownType) and resolve
349 * all available modules
353 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
354 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
355 if (!dirtyNodes.isEmpty()) {
356 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
357 if (nodeToResolve instanceof UnionTypeBuilder) {
358 // special handling for union types
359 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
360 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
361 // special handling for identityref types
362 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
363 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
365 resolveType(nodeToResolve, modules, module);
371 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
372 final ModuleBuilder module, SchemaContext context) {
373 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
374 if (!dirtyNodes.isEmpty()) {
375 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
376 if (nodeToResolve instanceof UnionTypeBuilder) {
377 // special handling for union types
378 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
379 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
380 // special handling for identityref types
381 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
382 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
384 resolveTypeWithContext(nodeToResolve, modules, module, context);
391 * Go through all augment definitions and perform augmentation. It is
392 * expected that modules are already sorted by their dependencies.
397 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
398 // collect augments from all loaded modules
399 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
400 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
401 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
402 allAugments.addAll(inner.getValue().getAllAugments());
406 for (int i = 0; i < allAugments.size(); i++) {
408 final AugmentationSchemaBuilder augment = allAugments.get(i);
409 // create collection of others
410 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
411 others.remove(augment);
414 boolean resolved = resolveAugment(modules, augment);
415 // while not resolved
417 while (!(resolved) && j < others.size()) {
418 // try to resolve next augment
419 resolveAugment(modules, others.get(j));
420 // then try to resolve first again
421 resolved = resolveAugment(modules, augment);
427 throw new YangParseException(augment.getModuleName(), augment.getLine(),
428 "Error in augment parsing: failed to find augment target");
434 * Search for augment target and perform augmentation.
438 * @param augmentBuilder
440 * @return true if target node found, false otherwise
442 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
443 final AugmentationSchemaBuilder augmentBuilder) {
444 if (augmentBuilder.isResolved()) {
448 int line = augmentBuilder.getLine();
449 ModuleBuilder module = getParentModule(augmentBuilder);
450 List<QName> path = augmentBuilder.getTargetPath().getPath();
451 Builder augmentParent = augmentBuilder.getParent();
453 Builder firstNodeParent = null;
454 if (augmentParent instanceof ModuleBuilder) {
455 // if augment is defined under module, parent of first node is
457 final QName firstNameInPath = path.get(0);
458 String prefix = firstNameInPath.getPrefix();
459 if (prefix == null) {
460 prefix = module.getPrefix();
462 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
463 } else if (augmentParent instanceof UsesNodeBuilder) {
464 firstNodeParent = augmentParent.getParent();
466 // augment can be defined only under module or uses
467 throw new YangParseException(augmentBuilder.getModuleName(), line,
468 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
471 return processAugmentation(augmentBuilder, firstNodeParent, path);
475 * Go through all augment definitions and resolve them. This method works in
476 * same way as {@link #resolveAugments(Map)} except that if target node is
477 * not found in loaded modules, it search for target node in given context.
482 * SchemaContext containing already resolved modules
484 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
485 final SchemaContext context) {
486 // collect augments from all loaded modules
487 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
488 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
489 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
490 allAugments.addAll(inner.getValue().getAllAugments());
494 for (int i = 0; i < allAugments.size(); i++) {
495 // pick augment from list
496 final AugmentationSchemaBuilder augment = allAugments.get(i);
498 boolean resolved = resolveAugmentWithContext(modules, augment, context);
499 // while not resolved
501 while (!(resolved) && j < allAugments.size()) {
502 // try to resolve next augment
503 resolveAugmentWithContext(modules, allAugments.get(j), context);
504 // then try to resolve first again
505 resolved = resolveAugmentWithContext(modules, augment, context);
510 throw new YangParseException(augment.getModuleName(), augment.getLine(),
511 "Error in augment parsing: failed to find augment target");
517 * Search for augment target and perform augmentation.
524 * SchemaContext containing already resolved modules
525 * @return true if target node found, false otherwise
527 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
528 final AugmentationSchemaBuilder augment, final SchemaContext context) {
529 if (augment.isResolved()) {
532 int line = augment.getLine();
533 ModuleBuilder module = getParentModule(augment);
534 List<QName> path = augment.getTargetPath().getPath();
535 final QName firstNameInPath = path.get(0);
536 String prefix = firstNameInPath.getPrefix();
537 if (prefix == null) {
538 prefix = module.getPrefix();
540 Builder augmentParent = augment.getParent();
541 Builder currentParent = null;
543 if (augmentParent instanceof ModuleBuilder) {
544 // if augment is defined under module, first parent is target module
545 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
546 } else if (augmentParent instanceof UsesNodeBuilder) {
547 currentParent = augmentParent.getParent();
549 // augment can be defined only under module or uses
550 throw new YangParseException(augment.getModuleName(), augment.getLine(),
551 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
554 if (currentParent == null) {
555 return processAugmentationOnContext(augment, path, module, prefix, context);
557 return processAugmentation(augment, currentParent, path);
562 * Go through identity statements defined in current module and resolve
563 * their 'base' statement if present.
568 * module being resolved
570 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
571 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
572 for (IdentitySchemaNodeBuilder identity : identities) {
573 final String baseIdentityName = identity.getBaseIdentityName();
574 if (baseIdentityName != null) {
575 String baseIdentityPrefix = null;
576 String baseIdentityLocalName = null;
577 if (baseIdentityName.contains(":")) {
578 final String[] splitted = baseIdentityName.split(":");
579 baseIdentityPrefix = splitted[0];
580 baseIdentityLocalName = splitted[1];
582 baseIdentityPrefix = module.getPrefix();
583 baseIdentityLocalName = baseIdentityName;
585 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
588 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
589 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
590 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
591 identity.setBaseIdentity(idBuilder);
599 * Go through identity statements defined in current module and resolve
600 * their 'base' statement. Method tries to find base identity in given
601 * modules. If base identity is not found, method will search it in context.
608 * SchemaContext containing already resolved modules
610 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
611 final ModuleBuilder module, final SchemaContext context) {
612 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
613 for (IdentitySchemaNodeBuilder identity : identities) {
614 final String baseIdentityName = identity.getBaseIdentityName();
615 if (baseIdentityName != null) {
616 String baseIdentityPrefix = null;
617 String baseIdentityLocalName = null;
618 if (baseIdentityName.contains(":")) {
619 final String[] splitted = baseIdentityName.split(":");
620 baseIdentityPrefix = splitted[0];
621 baseIdentityLocalName = splitted[1];
623 baseIdentityPrefix = module.getPrefix();
624 baseIdentityLocalName = baseIdentityName;
626 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
627 baseIdentityPrefix, identity.getLine());
629 if (dependentModuleBuilder == null) {
630 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
632 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
633 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
634 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
635 identity.setBaseIdentity(idNode);
639 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
641 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
642 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
643 identity.setBaseIdentity(idBuilder);
652 * Find and add reference of uses target grouping.
657 * SchemaContext containing already resolved modules or null if
658 * context is not available
660 private void findUsesTargets(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
661 final List<UsesNodeBuilder> allUses = new ArrayList<>();
662 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
663 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
664 allUses.addAll(inner.getValue().getAllUsesNodes());
667 for (UsesNodeBuilder usesNode : allUses) {
668 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
669 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
671 if (targetGroupingBuilder == null) {
672 if (context == null) {
673 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
674 + usesNode.getGroupingPathAsString() + "' not found.");
676 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
678 usesNode.setGroupingDefinition(targetGroupingDefinition);
681 usesNode.setGrouping(targetGroupingBuilder);
687 * Copy data from uses target. Augmentations have to be resolved already.
691 * @param resolveWithContext
692 * boolean value which says whether
693 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
694 * collectUsesDataFromContext} should be used for processing of
695 * individual uses node.
697 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final boolean resolveWithContext) {
698 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
699 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
700 ModuleBuilder module = inner.getValue();
701 List<UsesNodeBuilder> usesNodes = null;
702 boolean dataCollected = module.isAllUsesDataCollected();
704 while (!dataCollected) {
705 usesNodes = new ArrayList<>(module.getAllUsesNodes());
706 for (UsesNodeBuilder usesNode : usesNodes) {
707 if (!usesNode.isDataCollected()) {
708 if (resolveWithContext && usesNode.getGroupingBuilder() == null) {
709 GroupingUtils.collectUsesDataFromContext(usesNode);
711 GroupingUtils.collectUsesData(usesNode);
715 dataCollected = module.isAllUsesDataCollected();
719 resolvedUsesPostProcessing(modules, resolveWithContext);
723 * Update uses parent and perform refinement.
727 * @param resolveWithContext
728 * boolean value which says whether
729 * {@link GroupingUtils#collectUsesDataFromContext(UsesNodeBuilder)
730 * collectUsesDataFromContext} should be used for processing of
731 * individual uses node.
733 private void resolvedUsesPostProcessing(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
734 final boolean resolveWithContext) {
735 // new loop is must because in collecting data process new uses could
737 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
738 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
739 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
740 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
744 for (UsesNodeBuilder usesNode : allModulesUses) {
745 GroupingUtils.updateUsesParent(usesNode);
746 GroupingUtils.performRefine(usesNode);
748 for (UsesNodeBuilder usesNode : allModulesUses) {
749 GroupingUtils.fixUsesNodesPath(usesNode);
752 if (!resolveWithContext) {
753 for (UsesNodeBuilder usesNode : allModulesUses) {
754 if (usesNode.isCopy()) {
755 usesNode.getParent().getUsesNodes().remove(usesNode);
761 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
762 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
763 QName nodeType = usnb.getNodeType();
765 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
767 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
768 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
769 usnb.setNodeType(extension.getQName());
770 usnb.setExtensionBuilder(extension);
774 } catch (YangParseException e) {
775 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
776 + ": no such extension definition found.", e);
781 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
782 final ModuleBuilder module, final SchemaContext context) {
783 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
784 QName nodeType = usnb.getNodeType();
786 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
787 nodeType.getPrefix(), usnb.getLine());
789 if (dependentModuleBuilder == null) {
790 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
792 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
793 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
794 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
795 nodeType.getPrefix(), e.getQName().getLocalName()));
796 usnb.setExtensionDefinition(e);
801 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
802 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
803 usnb.setExtensionBuilder(extension);
809 } catch (YangParseException e) {
810 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
811 + ": no such extension definition found.", e);
818 * Traverse through modules and resolve their deviation statements.
823 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
824 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
825 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
826 ModuleBuilder b = inner.getValue();
827 resolveDeviation(modules, b);
833 * Traverse through module and resolve its deviation statements.
838 * module in which resolve deviations
840 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
841 for (DeviationBuilder dev : module.getDeviations()) {
842 int line = dev.getLine();
843 SchemaPath targetPath = dev.getTargetPath();
844 List<QName> path = targetPath.getPath();
845 QName q0 = path.get(0);
846 String prefix = q0.getPrefix();
847 if (prefix == null) {
848 prefix = module.getPrefix();
851 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
852 processDeviation(dev, dependentModuleBuilder, path, module);
857 * Traverse through modules and resolve their deviation statements with
863 * already resolved context
865 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
866 final SchemaContext context) {
867 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
868 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
869 ModuleBuilder b = inner.getValue();
870 resolveDeviationWithContext(modules, b, context);
876 * Traverse through module and resolve its deviation statements with given
882 * module in which resolve deviations
884 * already resolved context
886 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
887 final ModuleBuilder module, final SchemaContext context) {
888 for (DeviationBuilder dev : module.getDeviations()) {
889 int line = dev.getLine();
890 SchemaPath targetPath = dev.getTargetPath();
891 List<QName> path = targetPath.getPath();
892 QName q0 = path.get(0);
893 String prefix = q0.getPrefix();
894 if (prefix == null) {
895 prefix = module.getPrefix();
899 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
900 if (dependentModuleBuilder == null) {
901 Module dependentModule = findModuleFromContext(context, module, prefix, line);
902 Object currentParent = dependentModule;
904 for (int i = 0; i < path.size(); i++) {
905 if (currentParent == null) {
906 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
908 QName q = path.get(i);
909 name = q.getLocalName();
910 if (currentParent instanceof DataNodeContainer) {
911 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
915 if (currentParent == null) {
916 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
918 if (currentParent instanceof SchemaNode) {
919 dev.setTargetPath(((SchemaNode) currentParent).getPath());
923 processDeviation(dev, dependentModuleBuilder, path, module);
929 * Correct deviation target path in deviation builder.
933 * @param dependentModuleBuilder
934 * module containing deviation target
936 * current deviation target path
940 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
941 final List<QName> path, final ModuleBuilder module) {
942 final int line = dev.getLine();
943 Builder currentParent = dependentModuleBuilder;
945 for (int i = 0; i < path.size(); i++) {
946 if (currentParent == null) {
947 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
949 QName q = path.get(i);
950 String name = q.getLocalName();
951 if (currentParent instanceof DataNodeContainerBuilder) {
952 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
956 if (!(currentParent instanceof SchemaNodeBuilder)) {
957 throw new YangParseException(module.getName(), line, FAIL_DEVIATION_TARGET);
959 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());