2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.impl;
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
11 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.*;
14 import java.io.FileInputStream;
15 import java.io.FileNotFoundException;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Date;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.LinkedHashMap;
24 import java.util.List;
26 import java.util.Map.Entry;
28 import java.util.TreeMap;
30 import org.antlr.v4.runtime.ANTLRInputStream;
31 import org.antlr.v4.runtime.CommonTokenStream;
32 import org.antlr.v4.runtime.tree.ParseTree;
33 import org.antlr.v4.runtime.tree.ParseTreeWalker;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
39 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.Module;
41 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
44 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
45 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
46 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
47 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.util.CopyUtils;
62 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
63 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
64 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
65 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
66 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 import com.google.common.collect.Lists;
71 import com.google.common.collect.Maps;
72 import com.google.common.collect.Sets;
74 public final class YangParserImpl implements YangModelParser {
75 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
78 public Set<Module> parseYangModels(final List<File> yangFiles) {
79 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
83 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
85 throw new YangParseException("Not yet implemented");
86 // if (yangFiles != null) {
87 // final Map<InputStream, File> inputStreams = Maps.newHashMap();
89 // for (final File yangFile : yangFiles) {
91 // inputStreams.put(new FileInputStream(yangFile), yangFile);
92 // } catch (FileNotFoundException e) {
93 // LOG.warn("Exception while reading yang file: " + yangFile.getName(),
98 // Map<ModuleBuilder, InputStream> builderToStreamMap =
101 // final Map<String, TreeMap<Date, ModuleBuilder>> modules =
102 // resolveModuleBuilders(
103 // Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
105 // for (InputStream is : inputStreams.keySet()) {
108 // } catch (IOException e) {
109 // LOG.debug("Failed to close stream.");
113 // return new LinkedHashSet<Module>(buildWithContext(modules,
114 // context).values());
116 // return Collections.emptySet();
120 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
121 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
125 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
127 throw new YangParseException("Not yet implemented");
128 // if (yangModelStreams != null) {
129 // Map<ModuleBuilder, InputStream> builderToStreamMap =
130 // Maps.newHashMap();
131 // final Map<String, TreeMap<Date, ModuleBuilder>> modules =
132 // resolveModuleBuildersWithContext(
133 // yangModelStreams, builderToStreamMap, context);
134 // return new LinkedHashSet<Module>(buildWithContext(modules,
135 // context).values());
137 // return Collections.emptySet();
141 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
142 if (yangFiles != null) {
143 final Map<InputStream, File> inputStreams = Maps.newHashMap();
145 for (final File yangFile : yangFiles) {
147 inputStreams.put(new FileInputStream(yangFile), yangFile);
148 } catch (FileNotFoundException e) {
149 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
153 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
154 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
155 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
157 for (InputStream is : inputStreams.keySet()) {
160 } catch (IOException e) {
161 LOG.debug("Failed to close stream.");
165 Map<File, Module> retVal = Maps.newLinkedHashMap();
166 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
168 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
169 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
170 builderToModule.getValue());
175 return Collections.emptyMap();
179 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
180 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
182 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
184 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
185 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
187 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
188 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
194 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
195 return new SchemaContextImpl(modules);
198 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
199 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
201 final ParseTreeWalker walker = new ParseTreeWalker();
202 final List<ParseTree> trees = parseStreams(inputStreams);
203 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
206 new YangModelBasicValidator(walker).validate(trees);
208 YangParserListenerImpl yangModelParser = null;
209 for (int i = 0; i < trees.size(); i++) {
210 yangModelParser = new YangParserListenerImpl();
211 walker.walk(yangModelParser, trees.get(i));
212 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
214 // We expect the order of trees and streams has to be the same
215 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
216 builders[i] = moduleBuilder;
221 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
222 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
223 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
226 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
227 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
228 final SchemaContext context) {
229 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
231 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
232 // of items stored in map.
233 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
235 // module dependency graph sorted
236 List<ModuleBuilder> sorted = null;
237 if (context == null) {
238 sorted = ModuleDependencySort.sort(builders);
240 sorted = ModuleDependencySort.sortWithContext(context, builders);
243 for (final ModuleBuilder builder : sorted) {
244 if (builder == null) {
247 final String builderName = builder.getName();
248 Date builderRevision = builder.getRevision();
249 if (builderRevision == null) {
250 builderRevision = new Date(0L);
252 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
253 if (builderByRevision == null) {
254 builderByRevision = new TreeMap<Date, ModuleBuilder>();
256 builderByRevision.put(builderRevision, builder);
257 modules.put(builderName, builderByRevision);
262 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
263 final List<ParseTree> trees = new ArrayList<ParseTree>();
264 for (InputStream yangStream : yangStreams) {
265 trees.add(parseStream(yangStream));
270 private ParseTree parseStream(final InputStream yangStream) {
271 ParseTree result = null;
273 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
274 final YangLexer lexer = new YangLexer(input);
275 final CommonTokenStream tokens = new CommonTokenStream(lexer);
276 final YangParser parser = new YangParser(tokens);
277 parser.removeErrorListeners();
278 parser.addErrorListener(new YangErrorListener());
280 result = parser.yang();
281 } catch (IOException e) {
282 LOG.warn("Exception while reading yang file: " + yangStream, e);
287 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
288 findUsesTargets(modules, null);
290 // fix unresolved nodes
291 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
292 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
293 final ModuleBuilder moduleBuilder = childEntry.getValue();
294 fixUnresolvedNodes(modules, moduleBuilder);
298 finishResolveDirtyNodes(modules);
299 resolveAugments(modules);
300 resolveUses(modules);
301 resolveDeviations(modules);
304 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
305 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
306 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
307 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
308 final ModuleBuilder moduleBuilder = childEntry.getValue();
309 final Module module = moduleBuilder.build();
310 modulesByRevision.put(childEntry.getKey(), module);
311 result.put(moduleBuilder, module);
317 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
318 SchemaContext context) {
319 findUsesTargets(modules, context);
321 // fix unresolved nodes
322 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
323 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
324 final ModuleBuilder moduleBuilder = childEntry.getValue();
325 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
328 // TODO finishResolveDirtyNodesWithContext(modules, context)
329 resolveAugmentsWithContext(modules, context);
330 resolveUsesWithContext(modules, context);
331 resolveDeviationsWithContext(modules, context);
334 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
335 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
336 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
337 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
338 final ModuleBuilder moduleBuilder = childEntry.getValue();
339 final Module module = moduleBuilder.build();
340 modulesByRevision.put(childEntry.getKey(), module);
341 result.put(moduleBuilder, module);
347 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
348 resolveDirtyNodes(modules, builder);
349 resolveIdentities(modules, builder);
350 resolveUnknownNodes(modules, builder);
353 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
354 final ModuleBuilder builder, final SchemaContext context) {
355 resolveDirtyNodesWithContext(modules, builder, context);
356 resolveIdentitiesWithContext(modules, builder, context);
357 resolveUnknownNodesWithContext(modules, builder, context);
361 * Search for dirty nodes (node which contains UnknownType) and resolve
365 * all available modules
369 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
370 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
371 if (!dirtyNodes.isEmpty()) {
372 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
373 if (nodeToResolve instanceof UnionTypeBuilder) {
374 // special handling for union types
375 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
376 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
377 // special handling for identityref types
378 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
379 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
381 resolveType(nodeToResolve, modules, module);
387 private void finishResolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
388 final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
389 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
390 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
391 dirtyNodes.addAll(inner.getValue().getDirtyNodes());
395 if (!dirtyNodes.isEmpty()) {
396 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
397 if (nodeToResolve instanceof UnionTypeBuilder) {
398 List<TypeDefinitionBuilder> newTypes = new ArrayList<>();
399 List<TypeDefinitionBuilder> oldTypes = ((UnionTypeBuilder) nodeToResolve).getTypedefs();
400 for (TypeDefinitionBuilder tdb : oldTypes) {
401 TypeDefinitionBuilder newType = CopyUtils.copy(tdb, nodeToResolve, false);
402 ParserUtils.correctTypeAwareNodePath(newType);
403 newTypes.add(newType);
406 oldTypes.addAll(newTypes);
407 } else if (nodeToResolve.getType() instanceof IdentityrefType) {
408 TypeDefinition<?> idRef = ParserUtils.createCorrectTypeDefinition(nodeToResolve.getPath(),
409 nodeToResolve.getType());
410 nodeToResolve.setType(idRef);
412 TypeDefinitionBuilder tdb = CopyUtils.copy(nodeToResolve.getTypedef(), nodeToResolve, false);
413 ParserUtils.correctTypeAwareNodePath(tdb);
414 nodeToResolve.setTypedef(tdb);
420 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
421 final ModuleBuilder module, SchemaContext context) {
422 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
423 if (!dirtyNodes.isEmpty()) {
424 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
425 if (nodeToResolve instanceof UnionTypeBuilder) {
426 // special handling for union types
427 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
428 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
429 // special handling for identityref types
430 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
431 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
433 resolveTypeWithContext(nodeToResolve, modules, module, context);
440 * Go through all augment definitions and perform augmentation. It is
441 * expected that modules are already sorted by their dependencies.
446 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
447 // collect augments from all loaded modules
448 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
449 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
450 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
451 allAugments.addAll(inner.getValue().getAllAugments());
455 for (int i = 0; i < allAugments.size(); i++) {
457 final AugmentationSchemaBuilder augment = allAugments.get(i);
458 // create collection of others
459 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
460 others.remove(augment);
463 boolean resolved = resolveAugment(modules, augment);
464 // while not resolved
466 while (!(resolved) && j < others.size()) {
467 // try to resolve next augment
468 resolveAugment(modules, others.get(j));
469 // then try to resolve first again
470 resolved = resolveAugment(modules, augment);
476 throw new YangParseException(augment.getModuleName(), augment.getLine(),
477 "Error in augment parsing: failed to find augment target");
483 * Search for augment target and perform augmentation.
487 * @param augmentBuilder
489 * @return true if target node found, false otherwise
491 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
492 final AugmentationSchemaBuilder augmentBuilder) {
493 if (augmentBuilder.isResolved()) {
497 int line = augmentBuilder.getLine();
498 ModuleBuilder module = getParentModule(augmentBuilder);
499 List<QName> path = augmentBuilder.getTargetPath().getPath();
500 Builder augmentParent = augmentBuilder.getParent();
502 Builder firstNodeParent = null;
503 if (augmentParent instanceof ModuleBuilder) {
504 // if augment is defined under module, parent of first node is
506 final QName firstNameInPath = path.get(0);
507 String prefix = firstNameInPath.getPrefix();
508 if (prefix == null) {
509 prefix = module.getPrefix();
511 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
512 } else if (augmentParent instanceof UsesNodeBuilder) {
513 firstNodeParent = augmentParent.getParent();
515 // augment can be defined only under module or uses
516 throw new YangParseException(augmentBuilder.getModuleName(), line,
517 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
520 return processAugmentation(augmentBuilder, firstNodeParent, path);
524 * Go through all augment definitions and resolve them. This method works in
525 * same way as {@link #resolveAugments(Map)} except that if target node is
526 * not found in loaded modules, it search for target node in given context.
531 * SchemaContext containing already resolved modules
533 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
534 final SchemaContext context) {
535 // collect augments from all loaded modules
536 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
537 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
538 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
539 allAugments.addAll(inner.getValue().getAllAugments());
543 for (int i = 0; i < allAugments.size(); i++) {
544 // pick augment from list
545 final AugmentationSchemaBuilder augment = allAugments.get(i);
547 boolean resolved = resolveAugmentWithContext(modules, augment, context);
548 // while not resolved
550 while (!(resolved) && j < allAugments.size()) {
551 // try to resolve next augment
552 resolveAugmentWithContext(modules, allAugments.get(j), context);
553 // then try to resolve first again
554 resolved = resolveAugmentWithContext(modules, augment, context);
559 throw new YangParseException(augment.getModuleName(), augment.getLine(),
560 "Error in augment parsing: failed to find augment target");
566 * Search for augment target and perform augmentation.
570 * @param augmentBuilder
573 * SchemaContext containing already resolved modules
574 * @return true if target node found, false otherwise
576 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
577 final AugmentationSchemaBuilder augmentBuilder, final SchemaContext context) {
578 if (augmentBuilder.isResolved()) {
581 int line = augmentBuilder.getLine();
582 ModuleBuilder module = getParentModule(augmentBuilder);
583 List<QName> path = augmentBuilder.getTargetPath().getPath();
584 final QName firstNameInPath = path.get(0);
585 String prefix = firstNameInPath.getPrefix();
586 if (prefix == null) {
587 prefix = module.getPrefix();
589 Builder augmentParent = augmentBuilder.getParent();
590 Builder currentParent = null;
592 if (augmentParent instanceof ModuleBuilder) {
593 // if augment is defined under module, first parent is target module
594 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
595 } else if (augmentParent instanceof UsesNodeBuilder) {
596 currentParent = augmentParent.getParent();
598 // augment can be defined only under module or uses
599 throw new YangParseException(augmentBuilder.getModuleName(), augmentBuilder.getLine(),
600 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
603 if (currentParent == null) {
604 return processAugmentationOnContext(augmentBuilder, path, module, prefix, context);
606 return processAugmentation(augmentBuilder, currentParent, path);
611 * Go through identity statements defined in current module and resolve
612 * their 'base' statement if present.
617 * module being resolved
619 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
620 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
621 for (IdentitySchemaNodeBuilder identity : identities) {
622 final String baseIdentityName = identity.getBaseIdentityName();
623 if (baseIdentityName != null) {
624 String baseIdentityPrefix = null;
625 String baseIdentityLocalName = null;
626 if (baseIdentityName.contains(":")) {
627 final String[] splitted = baseIdentityName.split(":");
628 baseIdentityPrefix = splitted[0];
629 baseIdentityLocalName = splitted[1];
631 baseIdentityPrefix = module.getPrefix();
632 baseIdentityLocalName = baseIdentityName;
634 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
637 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
638 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
639 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
640 identity.setBaseIdentity(idBuilder);
648 * Go through identity statements defined in current module and resolve
649 * their 'base' statement. Method tries to find base identity in given
650 * modules. If base identity is not found, method will search it in context.
657 * SchemaContext containing already resolved modules
659 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
660 final ModuleBuilder module, final SchemaContext context) {
661 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
662 for (IdentitySchemaNodeBuilder identity : identities) {
663 final String baseIdentityName = identity.getBaseIdentityName();
664 if (baseIdentityName != null) {
665 String baseIdentityPrefix = null;
666 String baseIdentityLocalName = null;
667 if (baseIdentityName.contains(":")) {
668 final String[] splitted = baseIdentityName.split(":");
669 baseIdentityPrefix = splitted[0];
670 baseIdentityLocalName = splitted[1];
672 baseIdentityPrefix = module.getPrefix();
673 baseIdentityLocalName = baseIdentityName;
675 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
676 baseIdentityPrefix, identity.getLine());
678 if (dependentModuleBuilder == null) {
679 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
681 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
682 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
683 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
684 identity.setBaseIdentity(idNode);
688 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
690 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
691 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
692 identity.setBaseIdentity(idBuilder);
701 * Find target grouping for all uses nodes.
706 private void findUsesTargets(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
707 final List<UsesNodeBuilder> allUses = new ArrayList<>();
708 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
709 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
710 allUses.addAll(inner.getValue().getAllUsesNodes());
713 for (UsesNodeBuilder usesNode : allUses) {
714 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
715 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
717 if (targetGroupingBuilder == null) {
718 if (context == null) {
719 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
720 + usesNode.getGroupingName() + "' not found.");
722 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
724 usesNode.setGroupingDefinition(targetGroupingDefinition);
725 usesNode.setGroupingPath(targetGroupingDefinition.getPath());
728 usesNode.setGrouping(targetGroupingBuilder);
729 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
735 * Copy data from uses target, update uses parent and perform refinement.
736 * Augmentations have to be resolved already.
741 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
742 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
743 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
744 ModuleBuilder module = inner.getValue();
745 List<UsesNodeBuilder> usesNodes = null;
746 boolean dataCollected = module.isAllUsesDataCollected();
748 while (!dataCollected) {
749 usesNodes = new ArrayList<>(module.getAllUsesNodes());
750 for (UsesNodeBuilder usesNode : usesNodes) {
751 if (!usesNode.isDataCollected()) {
752 GroupingUtils.collectUsesData(usesNode);
755 dataCollected = module.isAllUsesDataCollected();
760 // new cycle is must because in collecting data process new uses could
762 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
763 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
764 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
765 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
769 for (UsesNodeBuilder usesNode : allModulesUses) {
770 GroupingUtils.updateUsesParent(usesNode);
771 GroupingUtils.performRefine(usesNode);
773 for (UsesNodeBuilder usesNode : allModulesUses) {
774 GroupingUtils.fixUsesNodesPath(usesNode);
783 * SchemaContext containing already resolved modules
785 private void resolveUsesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
786 final SchemaContext context) {
787 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
788 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
789 ModuleBuilder module = inner.getValue();
790 List<UsesNodeBuilder> usesNodes = null;
791 boolean dataCollected = module.isAllUsesDataCollected();
793 while (!dataCollected) {
794 usesNodes = new ArrayList<>(module.getAllUsesNodes());
795 for (UsesNodeBuilder usesNode : usesNodes) {
796 if (!usesNode.isDataCollected()) {
797 if (usesNode.getGroupingBuilder() == null) {
798 GroupingUtils.collectUsesDataFromContext(usesNode);
800 GroupingUtils.collectUsesData(usesNode);
804 dataCollected = module.isAllUsesDataCollected();
809 // new cycle is must because in collecting data process new uses could
811 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
812 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
813 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
814 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
818 for (UsesNodeBuilder usesNode : allModulesUses) {
819 GroupingUtils.updateUsesParent(usesNode);
820 GroupingUtils.performRefine(usesNode);
822 for (UsesNodeBuilder usesNode : allModulesUses) {
823 GroupingUtils.fixUsesNodesPath(usesNode);
827 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
828 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
829 QName nodeType = usnb.getNodeType();
830 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
832 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
834 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
835 nodeType.getPrefix(), nodeType.getLocalName());
836 usnb.setNodeType(newNodeType);
837 } catch (YangParseException e) {
838 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
844 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
845 final ModuleBuilder module, final SchemaContext context) {
846 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
847 QName nodeType = unknownNodeBuilder.getNodeType();
848 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
850 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
851 nodeType.getPrefix(), unknownNodeBuilder.getLine());
853 QName newNodeType = null;
854 if (dependentModuleBuilder == null) {
855 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
856 unknownNodeBuilder.getLine());
857 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
858 nodeType.getPrefix(), nodeType.getLocalName());
860 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
861 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
864 unknownNodeBuilder.setNodeType(newNodeType);
865 } catch (YangParseException e) {
866 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
874 * Traverse through modules and resolve their deviation statements.
879 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
880 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
881 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
882 ModuleBuilder b = inner.getValue();
883 resolveDeviation(modules, b);
889 * Traverse through module and resolve its deviation statements.
894 * module in which resolve deviations
896 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
897 for (DeviationBuilder dev : module.getDeviations()) {
898 int line = dev.getLine();
899 SchemaPath targetPath = dev.getTargetPath();
900 List<QName> path = targetPath.getPath();
901 QName q0 = path.get(0);
902 String prefix = q0.getPrefix();
903 if (prefix == null) {
904 prefix = module.getPrefix();
907 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
908 processDeviation(dev, dependentModuleBuilder, path, module);
913 * Traverse through modules and resolve their deviation statements with
919 * already resolved context
921 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
922 final SchemaContext context) {
923 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
924 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
925 ModuleBuilder b = inner.getValue();
926 resolveDeviationWithContext(modules, b, context);
932 * Traverse through module and resolve its deviation statements with given
938 * module in which resolve deviations
940 * already resolved context
942 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
943 final ModuleBuilder module, final SchemaContext context) {
944 for (DeviationBuilder dev : module.getDeviations()) {
945 int line = dev.getLine();
946 SchemaPath targetPath = dev.getTargetPath();
947 List<QName> path = targetPath.getPath();
948 QName q0 = path.get(0);
949 String prefix = q0.getPrefix();
950 if (prefix == null) {
951 prefix = module.getPrefix();
955 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
956 if (dependentModuleBuilder == null) {
957 Module dependentModule = findModuleFromContext(context, module, prefix, line);
958 Object currentParent = dependentModule;
960 for (int i = 0; i < path.size(); i++) {
961 if (currentParent == null) {
962 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
964 QName q = path.get(i);
965 name = q.getLocalName();
966 if (currentParent instanceof DataNodeContainer) {
967 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
971 if (currentParent == null) {
972 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
974 if (currentParent instanceof SchemaNode) {
975 dev.setTargetPath(((SchemaNode) currentParent).getPath());
979 processDeviation(dev, dependentModuleBuilder, path, module);
985 * Correct deviation target path in deviation builder.
989 * @param dependentModuleBuilder
990 * module containing deviation target
992 * current deviation target path
996 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
997 final List<QName> path, final ModuleBuilder module) {
998 final int line = dev.getLine();
999 Builder currentParent = dependentModuleBuilder;
1001 for (int i = 0; i < path.size(); i++) {
1002 if (currentParent == null) {
1003 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1005 QName q = path.get(i);
1006 String name = q.getLocalName();
1007 if (currentParent instanceof DataNodeContainerBuilder) {
1008 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1012 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1013 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1015 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());