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) {
435 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
437 // then try to resolve first module again
438 resolveAugment(modules, module);
444 * Tries to resolve augments in given module. If augment target node is not
448 * all available modules
452 private void resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
453 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
454 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
456 if (!augmentBuilder.isResolved()) {
457 final SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
458 final List<QName> path = augmentTargetSchemaPath.getPath();
460 final QName qname = path.get(0);
461 String prefix = qname.getPrefix();
462 if (prefix == null) {
463 prefix = module.getPrefix();
466 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix,
467 augmentBuilder.getLine());
468 processAugmentation(augmentBuilder, path, module, dependentModule);
476 * Go through all augment definitions and resolve them. This method works in
477 * same way as {@link #resolveAugments(Map)} except that if target node is
478 * not found in loaded modules, it search for target node in given context.
483 * SchemaContext containing already resolved modules
485 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
486 final SchemaContext context) {
487 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
488 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
489 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
490 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
491 allModulesList.add(inner.getValue());
492 allModulesSet.add(inner.getValue());
496 for (int i = 0; i < allModulesList.size(); i++) {
497 final ModuleBuilder module = allModulesList.get(i);
498 // try to resolve augments in module
499 resolveAugmentWithContext(modules, module, context);
500 // while all augments are not resolved
501 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet.iterator();
502 while (!(module.getAugmentsResolved() == module.getAllAugments().size())) {
503 ModuleBuilder nextModule = null;
504 // try resolve other module augments
506 nextModule = allModulesIterator.next();
507 resolveAugmentWithContext(modules, nextModule, context);
508 } catch (NoSuchElementException e) {
509 throw new YangParseException("Failed to resolve augments in module '" + module.getName() + "'.", e);
511 // then try to resolve first module again
512 resolveAugmentWithContext(modules, module, context);
518 * Tries to resolve augments in given module. If augment target node is not
522 * all available modules
526 private void resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
527 final ModuleBuilder module, final SchemaContext context) {
528 if (module.getAugmentsResolved() < module.getAllAugments().size()) {
530 for (AugmentationSchemaBuilder augmentBuilder : module.getAllAugments()) {
531 final int line = augmentBuilder.getLine();
533 if (!augmentBuilder.isResolved()) {
534 final List<QName> path = augmentBuilder.getTargetPath().getPath();
535 final QName qname = path.get(0);
536 String prefix = qname.getPrefix();
537 if (prefix == null) {
538 prefix = module.getPrefix();
541 // try to find augment target module in loaded modules...
542 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix,
544 if (dependentModuleBuilder == null) {
545 // perform augmentation on module from context and
546 // continue to next augment
547 processAugmentationOnContext(augmentBuilder, path, module, prefix, line, context);
550 processAugmentation(augmentBuilder, path, module, dependentModuleBuilder);
559 * Go through identity statements defined in current module and resolve
560 * their 'base' statement if present.
565 * module being resolved
567 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
568 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
569 for (IdentitySchemaNodeBuilder identity : identities) {
570 final String baseIdentityName = identity.getBaseIdentityName();
571 if (baseIdentityName != null) {
572 String baseIdentityPrefix = null;
573 String baseIdentityLocalName = null;
574 if (baseIdentityName.contains(":")) {
575 final String[] splitted = baseIdentityName.split(":");
576 baseIdentityPrefix = splitted[0];
577 baseIdentityLocalName = splitted[1];
579 baseIdentityPrefix = module.getPrefix();
580 baseIdentityLocalName = baseIdentityName;
582 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
585 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
586 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
587 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
588 identity.setBaseIdentity(idBuilder);
596 * Go through identity statements defined in current module and resolve
597 * their 'base' statement. Method tries to find base identity in given
598 * modules. If base identity is not found, method will search it in context.
605 * SchemaContext containing already resolved modules
607 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
608 final ModuleBuilder module, final SchemaContext context) {
609 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
610 for (IdentitySchemaNodeBuilder identity : identities) {
611 final String baseIdentityName = identity.getBaseIdentityName();
612 if (baseIdentityName != null) {
613 String baseIdentityPrefix = null;
614 String baseIdentityLocalName = null;
615 if (baseIdentityName.contains(":")) {
616 final String[] splitted = baseIdentityName.split(":");
617 baseIdentityPrefix = splitted[0];
618 baseIdentityLocalName = splitted[1];
620 baseIdentityPrefix = module.getPrefix();
621 baseIdentityLocalName = baseIdentityName;
623 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
624 baseIdentityPrefix, identity.getLine());
626 if (dependentModuleBuilder == null) {
627 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
629 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
630 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
631 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
632 identity.setBaseIdentity(idNode);
636 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
638 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
639 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
640 identity.setBaseIdentity(idBuilder);
649 * Go through uses statements defined in current module and resolve their
655 * module being resolved
657 private void resolveUsesNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
658 final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
659 for (UsesNodeBuilder usesNode : allModuleUses) {
660 // process uses operation
661 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
662 usesNode.setGroupingPath(targetGrouping.getPath());
663 processUsesNode(module, usesNode, targetGrouping);
665 for (RefineHolder refine : usesNode.getRefines()) {
666 DataSchemaNodeBuilder nodeToRefine = null;
667 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
668 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
673 if (nodeToRefine == null) {
674 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
675 + refine.getName() + "' not found");
677 if (nodeToRefine instanceof GroupingMember) {
678 ((GroupingMember) nodeToRefine).setAddedByUses(true);
680 RefineUtils.performRefine(nodeToRefine, refine);
681 usesNode.addRefineNode(nodeToRefine);
684 for (UsesNodeBuilder usesNode : allModuleUses) {
685 final GroupingBuilder targetGrouping = getTargetGroupingFromModules(usesNode, modules, module);
686 processUsesTarget(module, usesNode, targetGrouping);
691 * Tries to search target grouping in given modules and resolve refine
692 * nodes. If grouping is not found in modules, method tries to find it in
693 * modules from context.
700 * SchemaContext containing already resolved modules
702 private void resolveUsesNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
703 final ModuleBuilder module, final SchemaContext context) {
704 final List<UsesNodeBuilder> moduleUses = module.getAllUsesNodes();
705 for (UsesNodeBuilder usesNode : moduleUses) {
706 final GroupingBuilder targetGroupingBuilder = getTargetGroupingFromModules(usesNode, modules, module);
707 if (targetGroupingBuilder == null) {
708 final GroupingDefinition targetGrouping = getTargetGroupingFromContext(usesNode, module, context);
709 usesNode.setGroupingPath(targetGrouping.getPath());
710 processUsesNode(usesNode, targetGrouping);
711 for (RefineHolder refine : usesNode.getRefines()) {
712 DataSchemaNodeBuilder nodeToRefine = null;
713 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
714 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
719 if (nodeToRefine == null) {
720 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
721 + refine.getName() + "' not found");
723 if (nodeToRefine instanceof GroupingMember) {
724 ((GroupingMember) nodeToRefine).setAddedByUses(true);
726 RefineUtils.performRefine(nodeToRefine, refine);
727 usesNode.addRefineNode(nodeToRefine);
730 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
731 processUsesNode(module, usesNode, targetGroupingBuilder);
732 for (RefineHolder refine : usesNode.getRefines()) {
733 DataSchemaNodeBuilder nodeToRefine = null;
734 for (DataSchemaNodeBuilder dsnb : usesNode.getTargetChildren()) {
735 if (refine.getName().equals(dsnb.getQName().getLocalName())) {
740 if (nodeToRefine == null) {
741 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
742 + refine.getName() + "' not found");
744 if (nodeToRefine instanceof GroupingMember) {
745 ((GroupingMember) nodeToRefine).setAddedByUses(true);
747 RefineUtils.performRefine(nodeToRefine, refine);
748 usesNode.addRefineNode(nodeToRefine);
755 * Add nodes defined in target grouping to current context.
760 * @param targetGrouping
762 private void processUsesNode(final ModuleBuilder module, final UsesNodeBuilder usesNode,
763 final GroupingBuilder targetGrouping) {
764 DataNodeContainerBuilder parent = usesNode.getParent();
765 URI namespace = null;
766 Date revision = null;
767 String prefix = null;
768 if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
769 namespace = module.getNamespace();
770 revision = module.getRevision();
771 prefix = module.getPrefix();
773 QName parentQName = parent.getQName();
774 namespace = parentQName.getNamespace();
775 revision = parentQName.getRevision();
776 prefix = parentQName.getPrefix();
778 SchemaPath parentPath = parent.getPath();
780 Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode,
781 targetGrouping.getChildNodeBuilders(), parentPath, namespace, revision, prefix);
782 usesNode.getTargetChildren().addAll(newChildren);
784 Set<GroupingBuilder> newGroupings = processUsesGroupings(targetGrouping.getGroupingBuilders(), parentPath,
785 namespace, revision, prefix);
786 usesNode.getTargetGroupings().addAll(newGroupings);
788 Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(targetGrouping.getTypeDefinitionBuilders(),
789 parentPath, namespace, revision, prefix);
790 usesNode.getTargetTypedefs().addAll(newTypedefs);
792 List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(
793 targetGrouping.getUnknownNodeBuilders(), parentPath, namespace, revision, prefix);
794 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
798 * Check if target grouping contains uses nodes and if it does, merge
799 * current uses with them.
803 * @param targetGrouping
805 private void processUsesTarget(final ModuleBuilder module, final UsesNodeBuilder usesNode,
806 final GroupingBuilder targetGrouping) {
807 DataNodeContainerBuilder parent = usesNode.getParent();
808 URI namespace = null;
809 Date revision = null;
810 String prefix = null;
811 if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
812 namespace = module.getNamespace();
813 revision = module.getRevision();
814 prefix = module.getPrefix();
816 QName parentQName = parent.getQName();
817 namespace = parentQName.getNamespace();
818 revision = parentQName.getRevision();
819 prefix = parentQName.getPrefix();
821 SchemaPath parentPath = parent.getPath();
823 for (UsesNodeBuilder unb : targetGrouping.getUses()) {
824 Set<DataSchemaNodeBuilder> newChildren = processUsesDataSchemaNode(usesNode, unb.getTargetChildren(),
825 parentPath, namespace, revision, prefix);
826 usesNode.getTargetChildren().addAll(newChildren);
828 Set<GroupingBuilder> newGroupings = processUsesGroupings(unb.getTargetGroupings(), parentPath, namespace,
830 usesNode.getTargetGroupings().addAll(newGroupings);
832 Set<TypeDefinitionBuilder> newTypedefs = processUsesTypedefs(unb.getTargetTypedefs(), parentPath,
833 namespace, revision, prefix);
834 usesNode.getTargetTypedefs().addAll(newTypedefs);
836 List<UnknownSchemaNodeBuilder> newUnknownNodes = processUsesUnknownNodes(unb.getTargetUnknownNodes(),
837 parentPath, namespace, revision, prefix);
838 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
842 private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
843 final String moduleName = usesNode.getModuleName();
844 final int line = usesNode.getLine();
845 DataNodeContainerBuilder parent = usesNode.getParent();
846 URI namespace = null;
847 Date revision = null;
848 String prefix = null;
849 if (parent instanceof ModuleBuilder) {
850 ModuleBuilder m = (ModuleBuilder) parent;
851 namespace = m.getNamespace();
852 revision = m.getRevision();
853 prefix = m.getPrefix();
855 QName parentQName = parent.getQName();
856 namespace = parentQName.getNamespace();
857 revision = parentQName.getRevision();
858 prefix = parentQName.getPrefix();
860 SchemaPath parentPath = parent.getPath();
862 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
863 for (DataSchemaNode child : targetGrouping.getChildNodes()) {
865 DataSchemaNodeBuilder newChild = null;
866 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
867 if (child instanceof AnyXmlSchemaNode) {
868 newChild = createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
869 } else if (child instanceof ChoiceNode) {
870 newChild = createChoice((ChoiceNode) child, newQName, moduleName, line);
871 } else if (child instanceof ContainerSchemaNode) {
872 newChild = createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
873 } else if (child instanceof LeafListSchemaNode) {
874 newChild = createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
875 } else if (child instanceof LeafSchemaNode) {
876 newChild = createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
877 } else if (child instanceof ListSchemaNode) {
878 newChild = createList((ListSchemaNode) child, newQName, moduleName, line);
881 if (newChild == null) {
882 throw new YangParseException(moduleName, line,
883 "Unknown member of target grouping while resolving uses node.");
885 if (newChild instanceof GroupingMember) {
886 ((GroupingMember) newChild).setAddedByUses(true);
889 newChild.setPath(createSchemaPath(parentPath, newQName));
890 newChildren.add(newChild);
893 usesNode.getTargetChildren().addAll(newChildren);
895 final Set<GroupingBuilder> newGroupings = new HashSet<>();
896 for (GroupingDefinition g : targetGrouping.getGroupings()) {
897 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
898 GroupingBuilder newGrouping = createGrouping(g, newQName, moduleName, line);
899 newGrouping.setAddedByUses(true);
900 newGrouping.setPath(createSchemaPath(parentPath, newQName));
901 newGroupings.add(newGrouping);
903 usesNode.getTargetGroupings().addAll(newGroupings);
905 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
906 for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
907 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
908 TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, newQName, moduleName, line);
909 newType.setAddedByUses(true);
910 newType.setPath(createSchemaPath(parentPath, newQName));
911 newTypedefs.add(newType);
913 usesNode.getTargetTypedefs().addAll(newTypedefs);
915 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
916 for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
917 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
918 UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, newQName, moduleName, line);
919 newNode.setAddedByUses(true);
920 newNode.setPath(createSchemaPath(parentPath, newQName));
921 newUnknownNodes.add(newNode);
923 usesNode.getTargetUnknownNodes().addAll(newUnknownNodes);
926 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
927 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
928 QName nodeType = usnb.getNodeType();
929 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
931 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
933 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
934 nodeType.getPrefix(), nodeType.getLocalName());
935 usnb.setNodeType(newNodeType);
936 } catch (YangParseException e) {
937 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
943 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
944 final ModuleBuilder module, final SchemaContext context) {
945 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
946 QName nodeType = unknownNodeBuilder.getNodeType();
947 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
949 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
950 nodeType.getPrefix(), unknownNodeBuilder.getLine());
952 QName newNodeType = null;
953 if (dependentModuleBuilder == null) {
954 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
955 unknownNodeBuilder.getLine());
956 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
957 nodeType.getPrefix(), nodeType.getLocalName());
959 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
960 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
963 unknownNodeBuilder.setNodeType(newNodeType);
964 } catch (YangParseException e) {
965 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
973 * Traverse through modules and resolve their deviation statements.
978 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
979 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
980 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
981 ModuleBuilder b = inner.getValue();
982 resolveDeviation(modules, b);
988 * Traverse through module and resolve its deviation statements.
993 * module in which resolve deviations
995 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
996 for (DeviationBuilder dev : module.getDeviations()) {
997 int line = dev.getLine();
998 SchemaPath targetPath = dev.getTargetPath();
999 List<QName> path = targetPath.getPath();
1000 QName q0 = path.get(0);
1001 String prefix = q0.getPrefix();
1002 if (prefix == null) {
1003 prefix = module.getPrefix();
1006 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1007 processDeviation(dev, dependentModuleBuilder, path, module);
1012 * Traverse through modules and resolve their deviation statements with
1016 * all loaded modules
1018 * already resolved context
1020 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1021 final SchemaContext context) {
1022 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
1023 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
1024 ModuleBuilder b = inner.getValue();
1025 resolveDeviationWithContext(modules, b, context);
1031 * Traverse through module and resolve its deviation statements with given
1035 * all loaded modules
1037 * module in which resolve deviations
1039 * already resolved context
1041 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1042 final ModuleBuilder module, final SchemaContext context) {
1043 for (DeviationBuilder dev : module.getDeviations()) {
1044 int line = dev.getLine();
1045 SchemaPath targetPath = dev.getTargetPath();
1046 List<QName> path = targetPath.getPath();
1047 QName q0 = path.get(0);
1048 String prefix = q0.getPrefix();
1049 if (prefix == null) {
1050 prefix = module.getPrefix();
1054 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
1055 if (dependentModuleBuilder == null) {
1056 Module dependentModule = findModuleFromContext(context, module, prefix, line);
1057 Object currentParent = dependentModule;
1059 for (int i = 0; i < path.size(); i++) {
1060 if (currentParent == null) {
1061 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1063 QName q = path.get(i);
1064 name = q.getLocalName();
1065 if (currentParent instanceof DataNodeContainer) {
1066 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
1070 if (currentParent == null) {
1071 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1073 if (currentParent instanceof SchemaNode) {
1074 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1078 processDeviation(dev, dependentModuleBuilder, path, module);
1084 * Correct deviation target path in deviation builder.
1088 * @param dependentModuleBuilder
1089 * module containing deviation target
1091 * current deviation target path
1095 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1096 final List<QName> path, final ModuleBuilder module) {
1097 final int line = dev.getLine();
1098 Builder currentParent = dependentModuleBuilder;
1100 for (int i = 0; i < path.size(); i++) {
1101 if (currentParent == null) {
1102 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1104 QName q = path.get(i);
1105 String name = q.getLocalName();
1106 if (currentParent instanceof DataNodeContainerBuilder) {
1107 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1111 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1112 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1114 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());