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.Collections;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedHashSet;
27 import java.util.List;
29 import java.util.Map.Entry;
30 import java.util.NoSuchElementException;
32 import java.util.TreeMap;
34 import org.antlr.v4.runtime.ANTLRInputStream;
35 import org.antlr.v4.runtime.CommonTokenStream;
36 import org.antlr.v4.runtime.tree.ParseTree;
37 import org.antlr.v4.runtime.tree.ParseTreeWalker;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
43 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
45 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
47 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.Module;
52 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
53 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
55 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
57 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
58 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
59 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
60 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
66 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
68 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
69 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
70 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
71 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
72 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
73 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
74 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
75 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
76 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
77 import org.opendaylight.yangtools.yang.parser.util.RefineHolder;
78 import org.opendaylight.yangtools.yang.parser.util.RefineUtils;
79 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
80 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 import com.google.common.collect.Lists;
85 import com.google.common.collect.Maps;
86 import com.google.common.collect.Sets;
88 public final class YangParserImpl implements YangModelParser {
89 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
92 public Set<Module> parseYangModels(final List<File> yangFiles) {
93 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
97 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
98 if (yangFiles != null) {
99 final Map<InputStream, File> inputStreams = Maps.newHashMap();
101 for (final File yangFile : yangFiles) {
103 inputStreams.put(new FileInputStream(yangFile), yangFile);
104 } catch (FileNotFoundException e) {
105 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
109 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
111 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
112 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
114 for (InputStream is : inputStreams.keySet()) {
117 } catch (IOException e) {
118 LOG.debug("Failed to close stream.");
122 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
124 return Collections.emptySet();
128 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
129 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
133 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
134 if (yangModelStreams != null) {
135 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
136 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
137 yangModelStreams, builderToStreamMap, context);
138 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
140 return Collections.emptySet();
144 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
145 if (yangFiles != null) {
146 final Map<InputStream, File> inputStreams = Maps.newHashMap();
148 for (final File yangFile : yangFiles) {
150 inputStreams.put(new FileInputStream(yangFile), yangFile);
151 } catch (FileNotFoundException e) {
152 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
156 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
157 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
158 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
160 for (InputStream is : inputStreams.keySet()) {
163 } catch (IOException e) {
164 LOG.debug("Failed to close stream.");
168 Map<File, Module> retVal = Maps.newLinkedHashMap();
169 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
171 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
172 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
173 builderToModule.getValue());
178 return Collections.emptyMap();
182 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
183 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
185 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
187 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
188 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
190 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
191 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
197 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
198 return new SchemaContextImpl(modules);
201 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
202 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
204 final ParseTreeWalker walker = new ParseTreeWalker();
205 final List<ParseTree> trees = parseStreams(inputStreams);
206 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
209 new YangModelBasicValidator(walker).validate(trees);
211 YangParserListenerImpl yangModelParser = null;
212 for (int i = 0; i < trees.size(); i++) {
213 yangModelParser = new YangParserListenerImpl();
214 walker.walk(yangModelParser, trees.get(i));
215 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
217 // We expect the order of trees and streams has to be the same
218 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
219 builders[i] = moduleBuilder;
224 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
225 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
226 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
229 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
230 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
231 final SchemaContext context) {
232 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
234 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
235 // of items stored in map.
236 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
238 // module dependency graph sorted
239 List<ModuleBuilder> sorted = null;
240 if (context == null) {
241 sorted = ModuleDependencySort.sort(builders);
243 sorted = ModuleDependencySort.sortWithContext(context, builders);
246 for (final ModuleBuilder builder : sorted) {
247 if (builder == null) {
250 final String builderName = builder.getName();
251 Date builderRevision = builder.getRevision();
252 if (builderRevision == null) {
253 builderRevision = new Date(0L);
255 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
256 if (builderByRevision == null) {
257 builderByRevision = new TreeMap<Date, ModuleBuilder>();
259 builderByRevision.put(builderRevision, builder);
260 modules.put(builderName, builderByRevision);
265 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
266 final List<ParseTree> trees = new ArrayList<ParseTree>();
267 for (InputStream yangStream : yangStreams) {
268 trees.add(parseStream(yangStream));
273 private ParseTree parseStream(final InputStream yangStream) {
274 ParseTree result = null;
276 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
277 final YangLexer lexer = new YangLexer(input);
278 final CommonTokenStream tokens = new CommonTokenStream(lexer);
279 final YangParser parser = new YangParser(tokens);
280 parser.removeErrorListeners();
281 parser.addErrorListener(new YangErrorListener());
283 result = parser.yang();
284 } catch (IOException e) {
285 LOG.warn("Exception while reading yang file: " + yangStream, e);
290 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
291 // fix unresolved nodes
292 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
293 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
294 final ModuleBuilder moduleBuilder = childEntry.getValue();
295 fixUnresolvedNodes(modules, moduleBuilder);
298 resolveAugments(modules);
299 resolveDeviations(modules);
302 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
303 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
304 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
305 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
306 final ModuleBuilder moduleBuilder = childEntry.getValue();
307 final Module module = moduleBuilder.build();
308 modulesByRevision.put(childEntry.getKey(), module);
309 result.put(moduleBuilder, module);
315 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
316 SchemaContext context) {
317 // fix unresolved nodes
318 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
319 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
320 final ModuleBuilder moduleBuilder = childEntry.getValue();
321 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
324 resolveAugmentsWithContext(modules, context);
325 resolveDeviationsWithContext(modules, context);
328 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
329 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
330 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
331 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
332 final ModuleBuilder moduleBuilder = childEntry.getValue();
333 final Module module = moduleBuilder.build();
334 modulesByRevision.put(childEntry.getKey(), module);
335 result.put(moduleBuilder, module);
341 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
342 resolveDirtyNodes(modules, builder);
343 resolveIdentities(modules, builder);
344 resolveUsesNodes(modules, builder);
345 resolveUnknownNodes(modules, builder);
348 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
349 final ModuleBuilder builder, final SchemaContext context) {
350 resolveDirtyNodesWithContext(modules, builder, context);
351 resolveIdentitiesWithContext(modules, builder, context);
352 resolveUsesNodesWithContext(modules, builder, context);
353 resolveUnknownNodesWithContext(modules, builder, context);
357 * Search for dirty nodes (node which contains UnknownType) and resolve
361 * all available modules
365 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
366 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
367 if (!dirtyNodes.isEmpty()) {
368 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
369 if (nodeToResolve instanceof UnionTypeBuilder) {
370 // special handling for union types
371 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
372 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
373 // special handling for identityref types
374 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
375 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
377 resolveType(nodeToResolve, modules, module);
383 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
384 final ModuleBuilder module, SchemaContext context) {
385 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
386 if (!dirtyNodes.isEmpty()) {
387 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
388 if (nodeToResolve instanceof UnionTypeBuilder) {
389 // special handling for union types
390 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
391 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
392 // special handling for identityref types
393 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
394 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
396 resolveTypeWithContext(nodeToResolve, modules, module, context);
403 * Go through all augment definitions and resolve them. It is expected that
404 * modules are already sorted by their dependencies. This method also finds
405 * augment target node and add child nodes to it.
408 * all available modules
410 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
411 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
412 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
413 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
414 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
415 allModulesList.add(inner.getValue());
416 allModulesSet.add(inner.getValue());
420 for (int i = 0; i < allModulesList.size(); i++) {
421 final ModuleBuilder module = allModulesList.get(i);
422 // try to resolve augments in module
423 resolveAugment(modules, module);
424 // while all augments are not resolved
425 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
426 while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
427 ModuleBuilder nextModule = null;
428 // try resolve other module augments
430 nextModule = allModulesIterator.next();
431 resolveAugment(modules, nextModule);
432 } catch (NoSuchElementException e) {
433 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
435 // then try to resolve first module again
436 resolveAugment(modules, module);
442 * Tries to resolve augments in given module. If augment target node is not
446 * all available modules
450 private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
451 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
452 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
454 if (!augmentBuilder.isResolved()) {
455 final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
456 final List<QName> path = augmentTargetSchemaPath.getPath();
458 final QName qname = path.get(0);
459 String prefix = qname.getPrefix();
460 if (prefix == null) {
461 prefix = module.getPrefix();
464 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
465 augmentBuilder.getLine());
466 processAugmentation(augmentBuilder, path, module, dependentModule);
474 * Go through all augment definitions and resolve them. This method works in
475 * same way as {@link #resolveAugments(Map)} except that if target node is
476 * not found in loaded modules, it search for target node in given context.
481 * SchemaContext containing already resolved modules
483 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
484 final SchemaContext context) {
485 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
486 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
487 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
488 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
489 allModulesList.add(inner.getValue());
490 allModulesSet.add(inner.getValue());
494 for (int i = 0; i < allModulesList.size(); i++) {
495 final ModuleBuilder module = allModulesList.get(i);
496 // try to resolve augments in module
497 resolveAugmentWithContext(modules, module, context);
498 // while all augments are not resolved
499 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
500 while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
501 ModuleBuilder nextModule = null;
502 // try resolve other module augments
504 nextModule = allModulesIterator.next();
505 resolveAugmentWithContext(modules, nextModule, context);
506 } catch (NoSuchElementException e) {
507 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
509 // then try to resolve first module again
510 resolveAugmentWithContext(modules, module, context);
516 * Tries to resolve augments in given module. If augment target node is not
520 * all available modules
524 private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
525 final ModuleBuilder module, final SchemaContext context) {
526 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
528 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
529 final int line = augmentBuilder.getLine();
531 if (!augmentBuilder.isResolved()) {
532 final List<QName> path = augmentBuilder.getTargetPath().getPath();
533 final QName qname = path.get(0);
534 String prefix = qname.getPrefix();
535 if (prefix == null) {
536 prefix = module.getPrefix();
539 // try to find augment target module in loaded modules...
540 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
542 if (dependentModuleBuilder == null) {
543 // perform augmentation on module from context and
544 // continue to next augment
545 processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
548 processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
557 * Go through identity statements defined in current module and resolve
558 * their 'base' statement if present.
563 * module being resolved
565 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
566 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
567 for (IdentitySchemaNodeBuilder identity : identities) {
568 final String baseIdentityName = identity.getBaseIdentityName();
569 if (baseIdentityName != null) {
570 String baseIdentityPrefix = null;
571 String baseIdentityLocalName = null;
572 if (baseIdentityName.contains(":")) {
573 final String[] splitted = baseIdentityName.split(":");
574 baseIdentityPrefix = splitted[0];
575 baseIdentityLocalName = splitted[1];
577 baseIdentityPrefix = module.getPrefix();
578 baseIdentityLocalName = baseIdentityName;
580 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
583 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
584 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
585 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
586 identity.setBaseIdentity(idBuilder);
594 * Go through identity statements defined in current module and resolve
595 * their 'base' statement. Method tries to find base identity in given
596 * modules. If base identity is not found, method will search it in context.
603 * SchemaContext containing already resolved modules
605 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
606 final ModuleBuilder module, final SchemaContext context) {
607 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
608 for (IdentitySchemaNodeBuilder identity : identities) {
609 final String baseIdentityName = identity.getBaseIdentityName();
610 if (baseIdentityName != null) {
611 String baseIdentityPrefix = null;
612 String baseIdentityLocalName = null;
613 if (baseIdentityName.contains(":")) {
614 final String[] splitted = baseIdentityName.split(":");
615 baseIdentityPrefix = splitted[0];
616 baseIdentityLocalName = splitted[1];
618 baseIdentityPrefix = module.getPrefix();
619 baseIdentityLocalName = baseIdentityName;
621 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
622 baseIdentityPrefix, identity.getLine());
624 if (dependentModuleBuilder == null) {
625 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
627 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
628 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
629 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
630 identity.setBaseIdentity(idNode);
634 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
636 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
637 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
638 identity.setBaseIdentity(idBuilder);
647 * Go through uses statements defined in current module and resolve their
653 * module being resolved
655 private void resolveUsesNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
656 final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
657 for (UsesNodeBuilder usesNode : allModuleUses) {
658 // process uses operation
659 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
660 usesNode.setGroupingPath(targetGrouping.getPath());
661 processUsesNode(module, usesNode, targetGrouping);
663 for (RefineHolder refine : usesNode.getRefines()) {
664 DataSchemaNodeBuilder nodeToRefine = null;
665 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
666 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
671 if (nodeToRefine == null) {
672 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
673 + refine.getName() + "' not found");
675 if (nodeToRefine instanceof GroupingMember) {
676 ((GroupingMember) nodeToRefine).setAddedByUses(true);
678 RefineUtils.performRefine(nodeToRefine, refine);
679 usesNode.addRefineNode(nodeToRefine);
682 for (UsesNodeBuilder usesNode : allModuleUses) {
683 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
684 processUsesTarget(module, usesNode, targetGrouping);
689 * Tries to search target grouping in given modules and resolve refine
690 * nodes. If grouping is not found in modules, method tries to find it in
691 * modules from context.
698 * SchemaContext containing already resolved modules
700 private void resolveUsesNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
701 final ModuleBuilder module, final SchemaContext context) {
702 final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
703 for (UsesNodeBuilder usesNode : moduleUses) {
704 final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
705 if (targetGroupingBuilder == null) {
706 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
707 usesNode.setGroupingPath(targetGrouping.getPath());
708 processUsesNode(usesNode, targetGrouping);
709 for (RefineHolder refine : usesNode.getRefines()) {
710 DataSchemaNodeBuilder nodeToRefine = null;
711 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
712 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
717 if (nodeToRefine == null) {
718 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
719 + refine.getName() + "' not found");
721 if (nodeToRefine instanceof GroupingMember) {
722 ((GroupingMember) nodeToRefine).setAddedByUses(true);
724 RefineUtils.performRefine(nodeToRefine, refine);
725 usesNode.addRefineNode(nodeToRefine);
728 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
729 processUsesNode(module, usesNode, targetGroupingBuilder);
730 for (RefineHolder refine : usesNode.getRefines()) {
731 DataSchemaNodeBuilder nodeToRefine = null;
732 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
733 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
738 if (nodeToRefine == null) {
739 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
740 + refine.getName() + "' not found");
742 if (nodeToRefine instanceof GroupingMember) {
743 ((GroupingMember) nodeToRefine).setAddedByUses(true);
745 RefineUtils.performRefine(nodeToRefine, refine);
746 usesNode.addRefineNode(nodeToRefine);
753 * Add nodes defined in target grouping to current context.
758 * @param targetGrouping
760 private void processUsesNode(final ModuleBuilder module, final UsesNodeBuilder usesNode,
761 final GroupingBuilder targetGrouping) {
762 DataNodeContainerBuilder parent = usesNode.getParent();
763 URI namespace = null;
764 Date revision = null;
765 String prefix = null;
766 if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
767 namespace = module.getNamespace();
768 revision = module.getRevision();
769 prefix = module.getPrefix();
771 QName parentQName = parent.getQName();
772 namespace = parentQName.getNamespace();
773 revision = parentQName.getRevision();
774 prefix = parentQName.getPrefix();
776 SchemaPath parentPath = parent.getPath();
778 Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode,
779 targetGrouping.getChildNodeBuilders(), parentPath, namespace, revision, prefix);
780 usesNode.getTargetChildren().addAll(newChildren);
782 Set<GroupingBuilder> newGroupings = processUsesGroupings(targetGrouping.getGroupingBuilders(), parentPath,
783 namespace, revision, prefix);
784 usesNode.getTargetGroupings().addAll(newGroupings);
786 Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(targetGrouping.getTypeDefinitionBuilders(),
787 parentPath, namespace, revision, prefix);
788 usesNode.getTargetTypedefs().addAll(newTypedefs);
790 List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(
791 targetGrouping.getUnknownNodeBuilders(), parentPath, namespace, revision, prefix);
792 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
796 * Check if target grouping contains uses nodes and if it does, merge
797 * current uses with them.
801 * @param targetGrouping
803 private void processUsesTarget(final ModuleBuilder module, final UsesNodeBuilder usesNode,
804 final GroupingBuilder targetGrouping) {
805 DataNodeContainerBuilder parent = usesNode.getParent();
806 URI namespace = null;
807 Date revision = null;
808 String prefix = null;
809 if (parent instanceof ModuleBuilder) {
810 ModuleBuilder m = (ModuleBuilder) parent;
811 namespace = m.getNamespace();
812 revision = m.getRevision();
813 prefix = m.getPrefix();
815 QName parentQName = parent.getQName();
816 namespace = parentQName.getNamespace();
817 revision = parentQName.getRevision();
818 prefix = parentQName.getPrefix();
820 SchemaPath parentPath = parent.getPath();
822 for (UsesNodeBuilder unb : targetGrouping.getUses()) {
823 Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode, unb.getTargetChildren(),
824 parentPath, namespace, revision, prefix);
825 usesNode.getTargetChildren().addAll(newChildren);
827 Set<GroupingBuilder> newGroupings = processUsesGroupings(unb.getTargetGroupings(), parentPath, namespace,
829 usesNode.getTargetGroupings().addAll(newGroupings);
831 Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(unb.getTargetTypedefs(), parentPath,
832 namespace, revision, prefix);
833 usesNode.getTargetTypedefs().addAll(newTypedefs);
835 List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(unb.getTargetUnknownNodes(),
836 parentPath, namespace, revision, prefix);
837 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
841 private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
842 final String moduleName = usesNode.getModuleName();
843 final int line = usesNode.getLine();
844 DataNodeContainerBuilder parent = usesNode.getParent();
845 URI namespace = null;
846 Date revision = null;
847 String prefix = null;
848 if (parent instanceof ModuleBuilder) {
849 ModuleBuilder m = (ModuleBuilder) parent;
850 namespace = m.getNamespace();
851 revision = m.getRevision();
852 prefix = m.getPrefix();
854 QName parentQName = parent.getQName();
855 namespace = parentQName.getNamespace();
856 revision = parentQName.getRevision();
857 prefix = parentQName.getPrefix();
859 SchemaPath parentPath = parent.getPath();
861 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
862 for (DataSchemaNode child : targetGrouping.getChildNodes()) {
864 DataSchemaNodeBuilder newChild = null;
865 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
866 if (child instanceof AnyXmlSchemaNode) {
867 newChild = createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
868 } else if (child instanceof ChoiceNode) {
869 newChild = createChoice((ChoiceNode) child, newQName, moduleName, line);
870 } else if (child instanceof ContainerSchemaNode) {
871 newChild = createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
872 } else if (child instanceof LeafListSchemaNode) {
873 newChild = createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
874 } else if (child instanceof LeafSchemaNode) {
875 newChild = createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
876 } else if (child instanceof ListSchemaNode) {
877 newChild = createList((ListSchemaNode) child, newQName, moduleName, line);
880 if (newChild == null) {
881 throw new YangParseException(moduleName, line,
882 "Unknown member of target grouping while resolving uses node.");
884 if (newChild instanceof GroupingMember) {
885 ((GroupingMember) newChild).setAddedByUses(true);
888 newChild.setPath(createSchemaPath(parentPath, newQName));
889 newChildren.add(newChild);
892 usesNode.getTargetChildren().addAll(newChildren);
894 final Set<GroupingBuilder> newGroupings = new HashSet<>();
895 for (GroupingDefinition g : targetGrouping.getGroupings()) {
896 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
897 GroupingBuilder newGrouping = createGrouping(g, newQName, moduleName, line);
898 newGrouping.setAddedByUses(true);
899 newGrouping.setPath(createSchemaPath(parentPath, newQName));
900 newGroupings.add(newGrouping);
902 usesNode.getTargetGroupings().addAll(newGroupings);
904 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
905 for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
906 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
907 TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, newQName, moduleName, line);
908 newType.setAddedByUses(true);
909 newType.setPath(createSchemaPath(parentPath, newQName));
910 newTypedefs.add(newType);
912 usesNode.getTargetTypedefs().addAll(newTypedefs);
914 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
915 for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
916 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
917 UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, newQName, moduleName, line);
918 newNode.setAddedByUses(true);
919 newNode.setPath(createSchemaPath(parentPath, newQName));
920 newUnknownNodes.add(newNode);
922 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
925 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
926 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
927 QName nodeType = usnb.getNodeType();
928 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
930 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
932 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
933 nodeType.getPrefix(), nodeType.getLocalName());
934 usnb.setNodeType(newNodeType);
935 } catch (YangParseException e) {
936 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
942 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
943 final ModuleBuilder module, final SchemaContext context) {
944 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
945 QName nodeType = unknownNodeBuilder.getNodeType();
946 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
948 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
949 nodeType.getPrefix(), unknownNodeBuilder.getLine());
951 QName newNodeType = null;
952 if (dependentModuleBuilder == null) {
953 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
954 unknownNodeBuilder.getLine());
955 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
956 nodeType.getPrefix(), nodeType.getLocalName());
958 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
959 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
962 unknownNodeBuilder.setNodeType(newNodeType);
963 } catch (YangParseException e) {
964 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
972 * Traverse through modules and resolve their deviation statements.
977 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
978 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
979 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
980 ModuleBuilder b = inner.getValue();
981 resolveDeviation(modules, b);
987 * Traverse through module and resolve its deviation statements.
992 * module in which resolve deviations
994 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
995 for (DeviationBuilder dev : module.getDeviations()) {
996 int line = dev.getLine();
997 SchemaPath targetPath = dev.getTargetPath();
998 List<QName> path = targetPath.getPath();
999 QName q0 = path.get(0);
1000 String prefix = q0.getPrefix();
1001 if (prefix == null) {
1002 prefix = module.getPrefix();
1005 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1006 processDeviation(dev, dependentModuleBuilder, path, module);
1011 * Traverse through modules and resolve their deviation statements with
1015 * all loaded modules
1017 * already resolved context
1019 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1020 final SchemaContext context) {
1021 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1022 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1023 ModuleBuilder b = inner.getValue();
1024 resolveDeviationWithContext(modules, b, context);
1030 * Traverse through module and resolve its deviation statements with given
1034 * all loaded modules
1036 * module in which resolve deviations
1038 * already resolved context
1040 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1041 final ModuleBuilder module, final SchemaContext context) {
1042 for (DeviationBuilder dev : module.getDeviations()) {
1043 int line = dev.getLine();
1044 SchemaPath targetPath = dev.getTargetPath();
1045 List<QName> path = targetPath.getPath();
1046 QName q0 = path.get(0);
1047 String prefix = q0.getPrefix();
1048 if (prefix == null) {
1049 prefix = module.getPrefix();
1053 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1054 if (dependentModuleBuilder == null) {
1055 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1056 Object currentParent = dependentModule;
1058 for (int i = 0; i < path.size(); i++) {
1059 if (currentParent == null) {
1060 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1062 QName q = path.get(i);
1063 name = q.getLocalName();
1064 if (currentParent instanceof DataNodeContainer) {
1065 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1069 if (currentParent == null) {
1070 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1072 if (currentParent instanceof SchemaNode) {
1073 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1077 processDeviation(dev, dependentModuleBuilder, path, module);
1083 * Correct deviation target path in deviation builder.
1087 * @param dependentModuleBuilder
1088 * module containing deviation target
1090 * current deviation target path
1094 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1095 final List<QName> path, final ModuleBuilder module) {
1096 final int line = dev.getLine();
1097 Builder currentParent = dependentModuleBuilder;
1099 for (int i = 0; i < path.size(); i++) {
1100 if (currentParent == null) {
1101 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1103 QName q = path.get(i);
1104 String name = q.getLocalName();
1105 if (currentParent instanceof DataNodeContainerBuilder) {
1106 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1110 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1111 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1113 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());