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 || parent instanceof AugmentationSchemaBuilder) {
810 namespace = module.getNamespace();
811 revision = module.getRevision();
812 prefix = module.getPrefix();
814 QName parentQName = parent.getQName();
815 namespace = parentQName.getNamespace();
816 revision = parentQName.getRevision();
817 prefix = parentQName.getPrefix();
819 SchemaPath parentPath = parent.getPath();
821 for (UsesNodeBuilder unb : targetGrouping.getUses()) {
822 Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode, unb.getTargetChildren(),
823 parentPath, namespace, revision, prefix);
824 usesNode.getTargetChildren().addAll(newChildren);
826 Set<GroupingBuilder> newGroupings = processUsesGroupings(unb.getTargetGroupings(), parentPath, namespace,
828 usesNode.getTargetGroupings().addAll(newGroupings);
830 Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(unb.getTargetTypedefs(), parentPath,
831 namespace, revision, prefix);
832 usesNode.getTargetTypedefs().addAll(newTypedefs);
834 List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(unb.getTargetUnknownNodes(),
835 parentPath, namespace, revision, prefix);
836 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
840 private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
841 final String moduleName = usesNode.getModuleName();
842 final int line = usesNode.getLine();
843 DataNodeContainerBuilder parent = usesNode.getParent();
844 URI namespace = null;
845 Date revision = null;
846 String prefix = null;
847 if (parent instanceof ModuleBuilder) {
848 ModuleBuilder m = (ModuleBuilder) parent;
849 namespace = m.getNamespace();
850 revision = m.getRevision();
851 prefix = m.getPrefix();
853 QName parentQName = parent.getQName();
854 namespace = parentQName.getNamespace();
855 revision = parentQName.getRevision();
856 prefix = parentQName.getPrefix();
858 SchemaPath parentPath = parent.getPath();
860 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
861 for (DataSchemaNode child : targetGrouping.getChildNodes()) {
863 DataSchemaNodeBuilder newChild = null;
864 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
865 if (child instanceof AnyXmlSchemaNode) {
866 newChild = createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
867 } else if (child instanceof ChoiceNode) {
868 newChild = createChoice((ChoiceNode) child, newQName, moduleName, line);
869 } else if (child instanceof ContainerSchemaNode) {
870 newChild = createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
871 } else if (child instanceof LeafListSchemaNode) {
872 newChild = createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
873 } else if (child instanceof LeafSchemaNode) {
874 newChild = createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
875 } else if (child instanceof ListSchemaNode) {
876 newChild = createList((ListSchemaNode) child, newQName, moduleName, line);
879 if (newChild == null) {
880 throw new YangParseException(moduleName, line,
881 "Unknown member of target grouping while resolving uses node.");
883 if (newChild instanceof GroupingMember) {
884 ((GroupingMember) newChild).setAddedByUses(true);
887 newChild.setPath(createSchemaPath(parentPath, newQName));
888 newChildren.add(newChild);
891 usesNode.getTargetChildren().addAll(newChildren);
893 final Set<GroupingBuilder> newGroupings = new HashSet<>();
894 for (GroupingDefinition g : targetGrouping.getGroupings()) {
895 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
896 GroupingBuilder newGrouping = createGrouping(g, newQName, moduleName, line);
897 newGrouping.setAddedByUses(true);
898 newGrouping.setPath(createSchemaPath(parentPath, newQName));
899 newGroupings.add(newGrouping);
901 usesNode.getTargetGroupings().addAll(newGroupings);
903 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
904 for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
905 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
906 TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, newQName, moduleName, line);
907 newType.setAddedByUses(true);
908 newType.setPath(createSchemaPath(parentPath, newQName));
909 newTypedefs.add(newType);
911 usesNode.getTargetTypedefs().addAll(newTypedefs);
913 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
914 for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
915 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
916 UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, newQName, moduleName, line);
917 newNode.setAddedByUses(true);
918 newNode.setPath(createSchemaPath(parentPath, newQName));
919 newUnknownNodes.add(newNode);
921 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
924 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
925 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
926 QName nodeType = usnb.getNodeType();
927 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
929 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
931 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
932 nodeType.getPrefix(), nodeType.getLocalName());
933 usnb.setNodeType(newNodeType);
934 } catch (YangParseException e) {
935 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
941 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
942 final ModuleBuilder module, final SchemaContext context) {
943 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
944 QName nodeType = unknownNodeBuilder.getNodeType();
945 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
947 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
948 nodeType.getPrefix(), unknownNodeBuilder.getLine());
950 QName newNodeType = null;
951 if (dependentModuleBuilder == null) {
952 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
953 unknownNodeBuilder.getLine());
954 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
955 nodeType.getPrefix(), nodeType.getLocalName());
957 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
958 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
961 unknownNodeBuilder.setNodeType(newNodeType);
962 } catch (YangParseException e) {
963 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
971 * Traverse through modules and resolve their deviation statements.
976 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
977 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
978 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
979 ModuleBuilder b = inner.getValue();
980 resolveDeviation(modules, b);
986 * Traverse through module and resolve its deviation statements.
991 * module in which resolve deviations
993 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
994 for (DeviationBuilder dev : module.getDeviations()) {
995 int line = dev.getLine();
996 SchemaPath targetPath = dev.getTargetPath();
997 List<QName> path = targetPath.getPath();
998 QName q0 = path.get(0);
999 String prefix = q0.getPrefix();
1000 if (prefix == null) {
1001 prefix = module.getPrefix();
1004 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1005 processDeviation(dev, dependentModuleBuilder, path, module);
1010 * Traverse through modules and resolve their deviation statements with
1014 * all loaded modules
1016 * already resolved context
1018 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1019 final SchemaContext context) {
1020 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1021 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1022 ModuleBuilder b = inner.getValue();
1023 resolveDeviationWithContext(modules, b, context);
1029 * Traverse through module and resolve its deviation statements with given
1033 * all loaded modules
1035 * module in which resolve deviations
1037 * already resolved context
1039 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1040 final ModuleBuilder module, final SchemaContext context) {
1041 for (DeviationBuilder dev : module.getDeviations()) {
1042 int line = dev.getLine();
1043 SchemaPath targetPath = dev.getTargetPath();
1044 List<QName> path = targetPath.getPath();
1045 QName q0 = path.get(0);
1046 String prefix = q0.getPrefix();
1047 if (prefix == null) {
1048 prefix = module.getPrefix();
1052 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1053 if (dependentModuleBuilder == null) {
1054 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1055 Object currentParent = dependentModule;
1057 for (int i = 0; i < path.size(); i++) {
1058 if (currentParent == null) {
1059 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1061 QName q = path.get(i);
1062 name = q.getLocalName();
1063 if (currentParent instanceof DataNodeContainer) {
1064 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1068 if (currentParent == null) {
1069 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1071 if (currentParent instanceof SchemaNode) {
1072 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1076 processDeviation(dev, dependentModuleBuilder, path, module);
1082 * Correct deviation target path in deviation builder.
1086 * @param dependentModuleBuilder
1087 * module containing deviation target
1089 * current deviation target path
1093 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1094 final List<QName> path, final ModuleBuilder module) {
1095 final int line = dev.getLine();
1096 Builder currentParent = dependentModuleBuilder;
1098 for (int i = 0; i < path.size(); i++) {
1099 if (currentParent == null) {
1100 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1102 QName q = path.get(i);
1103 String name = q.getLocalName();
1104 if (currentParent instanceof DataNodeContainerBuilder) {
1105 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1109 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1110 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1112 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());