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.LinkedHashSet;
25 import java.util.List;
27 import java.util.Map.Entry;
29 import java.util.TreeMap;
31 import org.antlr.v4.runtime.ANTLRInputStream;
32 import org.antlr.v4.runtime.CommonTokenStream;
33 import org.antlr.v4.runtime.tree.ParseTree;
34 import org.antlr.v4.runtime.tree.ParseTreeWalker;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
37 import org.opendaylight.yangtools.yang.common.QName;
38 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
39 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
40 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
41 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.Module;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
46 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
47 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
48 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
49 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
59 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
63 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.util.CopyUtils;
65 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
66 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
67 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
68 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
69 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
73 import com.google.common.collect.Lists;
74 import com.google.common.collect.Maps;
75 import com.google.common.collect.Sets;
77 public final class YangParserImpl implements YangModelParser {
78 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
81 public Set<Module> parseYangModels(final List<File> yangFiles) {
82 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
86 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
87 if (yangFiles != null) {
88 final Map<InputStream, File> inputStreams = Maps.newHashMap();
90 for (final File yangFile : yangFiles) {
92 inputStreams.put(new FileInputStream(yangFile), yangFile);
93 } catch (FileNotFoundException e) {
94 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
98 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
100 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
101 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
103 for (InputStream is : inputStreams.keySet()) {
106 } catch (IOException e) {
107 LOG.debug("Failed to close stream.");
111 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
113 return Collections.emptySet();
117 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
118 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
122 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
123 if (yangModelStreams != null) {
124 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
125 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
126 yangModelStreams, builderToStreamMap, context);
127 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
129 return Collections.emptySet();
133 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
134 if (yangFiles != null) {
135 final Map<InputStream, File> inputStreams = Maps.newHashMap();
137 for (final File yangFile : yangFiles) {
139 inputStreams.put(new FileInputStream(yangFile), yangFile);
140 } catch (FileNotFoundException e) {
141 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
145 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
146 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
147 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
149 for (InputStream is : inputStreams.keySet()) {
152 } catch (IOException e) {
153 LOG.debug("Failed to close stream.");
157 Map<File, Module> retVal = Maps.newLinkedHashMap();
158 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
160 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
161 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
162 builderToModule.getValue());
167 return Collections.emptyMap();
171 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
172 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
174 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
176 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
177 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
179 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
180 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
186 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
187 return new SchemaContextImpl(modules);
190 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
191 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
193 final ParseTreeWalker walker = new ParseTreeWalker();
194 final List<ParseTree> trees = parseStreams(inputStreams);
195 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
198 new YangModelBasicValidator(walker).validate(trees);
200 YangParserListenerImpl yangModelParser = null;
201 for (int i = 0; i < trees.size(); i++) {
202 yangModelParser = new YangParserListenerImpl();
203 walker.walk(yangModelParser, trees.get(i));
204 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
206 // We expect the order of trees and streams has to be the same
207 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
208 builders[i] = moduleBuilder;
213 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
214 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
215 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
218 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
219 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
220 final SchemaContext context) {
221 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
223 // LinkedHashMap must be used to preserve order
224 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
226 // module dependency graph sorted
227 List<ModuleBuilder> sorted = null;
228 if (context == null) {
229 sorted = ModuleDependencySort.sort(builders);
231 sorted = ModuleDependencySort.sortWithContext(context, builders);
234 for (final ModuleBuilder builder : sorted) {
235 if (builder == null) {
238 final String builderName = builder.getName();
239 Date builderRevision = builder.getRevision();
240 if (builderRevision == null) {
241 builderRevision = new Date(0L);
243 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
244 if (builderByRevision == null) {
245 builderByRevision = new TreeMap<Date, ModuleBuilder>();
247 builderByRevision.put(builderRevision, builder);
248 modules.put(builderName, builderByRevision);
253 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
254 final List<ParseTree> trees = new ArrayList<ParseTree>();
255 for (InputStream yangStream : yangStreams) {
256 trees.add(parseStream(yangStream));
261 private ParseTree parseStream(final InputStream yangStream) {
262 ParseTree result = null;
264 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
265 final YangLexer lexer = new YangLexer(input);
266 final CommonTokenStream tokens = new CommonTokenStream(lexer);
267 final YangParser parser = new YangParser(tokens);
268 parser.removeErrorListeners();
269 parser.addErrorListener(new YangErrorListener());
271 result = parser.yang();
272 } catch (IOException e) {
273 LOG.warn("Exception while reading yang file: " + yangStream, e);
278 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
279 findUsesTargets(modules, null);
281 // fix unresolved nodes
282 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
283 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
284 final ModuleBuilder moduleBuilder = childEntry.getValue();
285 fixUnresolvedNodes(modules, moduleBuilder);
288 finishResolveDirtyNodes(modules);
289 resolveAugments(modules);
290 resolveUses(modules);
291 resolveDeviations(modules);
294 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
295 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
296 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
297 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
298 final ModuleBuilder moduleBuilder = childEntry.getValue();
299 final Module module = moduleBuilder.build();
300 modulesByRevision.put(childEntry.getKey(), module);
301 result.put(moduleBuilder, module);
307 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
308 SchemaContext context) {
309 findUsesTargets(modules, context);
311 // fix unresolved nodes
312 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
313 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
314 final ModuleBuilder moduleBuilder = childEntry.getValue();
315 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
318 finishResolveDirtyNodes(modules);
319 resolveAugmentsWithContext(modules, context);
320 resolveUsesWithContext(modules, context);
321 resolveDeviationsWithContext(modules, context);
324 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
325 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
326 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
327 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
328 final ModuleBuilder moduleBuilder = childEntry.getValue();
329 final Module module = moduleBuilder.build();
330 modulesByRevision.put(childEntry.getKey(), module);
331 result.put(moduleBuilder, module);
337 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
338 resolveDirtyNodes(modules, builder);
339 resolveIdentities(modules, builder);
340 resolveUnknownNodes(modules, builder);
343 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
344 final ModuleBuilder builder, final SchemaContext context) {
345 resolveDirtyNodesWithContext(modules, builder, context);
346 resolveIdentitiesWithContext(modules, builder, context);
347 resolveUnknownNodesWithContext(modules, builder, context);
351 * Search for dirty nodes (node which contains UnknownType) and resolve
355 * all available modules
359 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
360 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
361 if (!dirtyNodes.isEmpty()) {
362 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
363 if (nodeToResolve instanceof UnionTypeBuilder) {
364 // special handling for union types
365 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
366 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
367 // special handling for identityref types
368 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
369 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
371 resolveType(nodeToResolve, modules, module);
377 private void finishResolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
378 final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
379 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
380 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
381 dirtyNodes.addAll(inner.getValue().getDirtyNodes());
385 if (!dirtyNodes.isEmpty()) {
386 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
387 if (nodeToResolve instanceof UnionTypeBuilder) {
388 List<TypeDefinitionBuilder> newTypes = new ArrayList<>();
389 List<TypeDefinitionBuilder> oldTypes = ((UnionTypeBuilder) nodeToResolve).getTypedefs();
390 for (TypeDefinitionBuilder tdb : oldTypes) {
391 TypeDefinitionBuilder newType = CopyUtils.copy(tdb, nodeToResolve, false);
392 ParserUtils.correctTypeAwareNodePath(newType);
393 newTypes.add(newType);
396 oldTypes.addAll(newTypes);
397 } else if (nodeToResolve.getType() instanceof IdentityrefType) {
398 TypeDefinition<?> idRef = ParserUtils.createCorrectTypeDefinition(nodeToResolve.getPath(),
399 nodeToResolve.getType());
400 nodeToResolve.setType(idRef);
402 if (nodeToResolve.getType() == null) {
403 TypeDefinitionBuilder tdb = CopyUtils.copy(nodeToResolve.getTypedef(), nodeToResolve, false);
404 ParserUtils.correctTypeAwareNodePath(tdb);
405 nodeToResolve.setTypedef(tdb);
407 TypeDefinition<?> td = ParserUtils.createCorrectTypeDefinition(nodeToResolve.getPath(),
408 nodeToResolve.getType());
409 nodeToResolve.setType(td);
416 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
417 final ModuleBuilder module, SchemaContext context) {
418 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
419 if (!dirtyNodes.isEmpty()) {
420 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
421 if (nodeToResolve instanceof UnionTypeBuilder) {
422 // special handling for union types
423 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
424 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
425 // special handling for identityref types
426 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
427 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
429 resolveTypeWithContext(nodeToResolve, modules, module, context);
436 * Go through all augment definitions and perform augmentation. It is
437 * expected that modules are already sorted by their dependencies.
442 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
443 // collect augments from all loaded modules
444 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
445 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
446 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
447 allAugments.addAll(inner.getValue().getAllAugments());
451 for (int i = 0; i < allAugments.size(); i++) {
453 final AugmentationSchemaBuilder augment = allAugments.get(i);
454 // create collection of others
455 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
456 others.remove(augment);
459 boolean resolved = resolveAugment(modules, augment);
460 // while not resolved
462 while (!(resolved) && j < others.size()) {
463 // try to resolve next augment
464 resolveAugment(modules, others.get(j));
465 // then try to resolve first again
466 resolved = resolveAugment(modules, augment);
472 throw new YangParseException(augment.getModuleName(), augment.getLine(),
473 "Error in augment parsing: failed to find augment target");
479 * Search for augment target and perform augmentation.
483 * @param augmentBuilder
485 * @return true if target node found, false otherwise
487 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
488 final AugmentationSchemaBuilder augmentBuilder) {
489 if (augmentBuilder.isResolved()) {
493 int line = augmentBuilder.getLine();
494 ModuleBuilder module = getParentModule(augmentBuilder);
495 List<QName> path = augmentBuilder.getTargetPath().getPath();
496 Builder augmentParent = augmentBuilder.getParent();
498 Builder firstNodeParent = null;
499 if (augmentParent instanceof ModuleBuilder) {
500 // if augment is defined under module, parent of first node is
502 final QName firstNameInPath = path.get(0);
503 String prefix = firstNameInPath.getPrefix();
504 if (prefix == null) {
505 prefix = module.getPrefix();
507 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
508 } else if (augmentParent instanceof UsesNodeBuilder) {
509 firstNodeParent = augmentParent.getParent();
511 // augment can be defined only under module or uses
512 throw new YangParseException(augmentBuilder.getModuleName(), line,
513 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
516 return processAugmentation(augmentBuilder, firstNodeParent, path);
520 * Go through all augment definitions and resolve them. This method works in
521 * same way as {@link #resolveAugments(Map)} except that if target node is
522 * not found in loaded modules, it search for target node in given context.
527 * SchemaContext containing already resolved modules
529 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
530 final SchemaContext context) {
531 // collect augments from all loaded modules
532 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
533 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
534 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
535 allAugments.addAll(inner.getValue().getAllAugments());
539 for (int i = 0; i < allAugments.size(); i++) {
540 // pick augment from list
541 final AugmentationSchemaBuilder augment = allAugments.get(i);
543 boolean resolved = resolveAugmentWithContext(modules, augment, context);
544 // while not resolved
546 while (!(resolved) && j < allAugments.size()) {
547 // try to resolve next augment
548 resolveAugmentWithContext(modules, allAugments.get(j), context);
549 // then try to resolve first again
550 resolved = resolveAugmentWithContext(modules, augment, context);
555 throw new YangParseException(augment.getModuleName(), augment.getLine(),
556 "Error in augment parsing: failed to find augment target");
562 * Search for augment target and perform augmentation.
569 * SchemaContext containing already resolved modules
570 * @return true if target node found, false otherwise
572 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
573 final AugmentationSchemaBuilder augment, final SchemaContext context) {
574 if (augment.isResolved()) {
577 int line = augment.getLine();
578 ModuleBuilder module = getParentModule(augment);
579 List<QName> path = augment.getTargetPath().getPath();
580 final QName firstNameInPath = path.get(0);
581 String prefix = firstNameInPath.getPrefix();
582 if (prefix == null) {
583 prefix = module.getPrefix();
585 Builder augmentParent = augment.getParent();
586 Builder currentParent = null;
588 if (augmentParent instanceof ModuleBuilder) {
589 // if augment is defined under module, first parent is target module
590 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
591 } else if (augmentParent instanceof UsesNodeBuilder) {
592 currentParent = augmentParent.getParent();
594 // augment can be defined only under module or uses
595 throw new YangParseException(augment.getModuleName(), augment.getLine(),
596 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
599 if (currentParent == null) {
600 return processAugmentationOnContext(augment, path, module, prefix, context);
602 return processAugmentation(augment, currentParent, path);
607 * Go through identity statements defined in current module and resolve
608 * their 'base' statement if present.
613 * module being resolved
615 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
616 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
617 for (IdentitySchemaNodeBuilder identity : identities) {
618 final String baseIdentityName = identity.getBaseIdentityName();
619 if (baseIdentityName != null) {
620 String baseIdentityPrefix = null;
621 String baseIdentityLocalName = null;
622 if (baseIdentityName.contains(":")) {
623 final String[] splitted = baseIdentityName.split(":");
624 baseIdentityPrefix = splitted[0];
625 baseIdentityLocalName = splitted[1];
627 baseIdentityPrefix = module.getPrefix();
628 baseIdentityLocalName = baseIdentityName;
630 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
633 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
634 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
635 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
636 identity.setBaseIdentity(idBuilder);
644 * Go through identity statements defined in current module and resolve
645 * their 'base' statement. Method tries to find base identity in given
646 * modules. If base identity is not found, method will search it in context.
653 * SchemaContext containing already resolved modules
655 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
656 final ModuleBuilder module, final SchemaContext context) {
657 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
658 for (IdentitySchemaNodeBuilder identity : identities) {
659 final String baseIdentityName = identity.getBaseIdentityName();
660 if (baseIdentityName != null) {
661 String baseIdentityPrefix = null;
662 String baseIdentityLocalName = null;
663 if (baseIdentityName.contains(":")) {
664 final String[] splitted = baseIdentityName.split(":");
665 baseIdentityPrefix = splitted[0];
666 baseIdentityLocalName = splitted[1];
668 baseIdentityPrefix = module.getPrefix();
669 baseIdentityLocalName = baseIdentityName;
671 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
672 baseIdentityPrefix, identity.getLine());
674 if (dependentModuleBuilder == null) {
675 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
677 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
678 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
679 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
680 identity.setBaseIdentity(idNode);
684 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
686 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
687 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
688 identity.setBaseIdentity(idBuilder);
697 * Find target grouping for all uses nodes.
702 * SchemaContext containing already resolved modules or null if
703 * context is not available
705 private void findUsesTargets(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
706 final List<UsesNodeBuilder> allUses = new ArrayList<>();
707 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
708 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
709 allUses.addAll(inner.getValue().getAllUsesNodes());
712 for (UsesNodeBuilder usesNode : allUses) {
713 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
714 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
716 if (targetGroupingBuilder == null) {
717 if (context == null) {
718 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
719 + usesNode.getGroupingName() + "' not found.");
721 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
723 usesNode.setGroupingDefinition(targetGroupingDefinition);
724 usesNode.setGroupingPath(targetGroupingDefinition.getPath());
727 usesNode.setGrouping(targetGroupingBuilder);
728 usesNode.setGroupingPath(targetGroupingBuilder.getPath());
734 * Copy data from uses target, update uses parent and perform refinement.
735 * Augmentations have to be resolved already.
740 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
741 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
742 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
743 ModuleBuilder module = inner.getValue();
744 List<UsesNodeBuilder> usesNodes = null;
745 boolean dataCollected = module.isAllUsesDataCollected();
747 while (!dataCollected) {
748 usesNodes = new ArrayList<>(module.getAllUsesNodes());
749 for (UsesNodeBuilder usesNode : usesNodes) {
750 if (!usesNode.isDataCollected()) {
751 GroupingUtils.collectUsesData(usesNode);
754 dataCollected = module.isAllUsesDataCollected();
759 // new cycle is must because in collecting data process new uses could
761 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
762 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
763 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
764 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
768 for (UsesNodeBuilder usesNode : allModulesUses) {
769 GroupingUtils.updateUsesParent(usesNode);
770 GroupingUtils.performRefine(usesNode);
772 for (UsesNodeBuilder usesNode : allModulesUses) {
773 GroupingUtils.fixUsesNodesPath(usesNode);
776 for (UsesNodeBuilder usesNode : allModulesUses) {
777 if (usesNode.isCopy()) {
778 usesNode.getParent().getUsesNodes().remove(usesNode);
784 * Copy data from uses target, update uses parent and perform refinement.
785 * Augmentations have to be resolved already.
790 * SchemaContext containing already resolved modules
792 private void resolveUsesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
793 final SchemaContext context) {
794 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
795 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
796 ModuleBuilder module = inner.getValue();
797 List<UsesNodeBuilder> usesNodes = null;
798 boolean dataCollected = module.isAllUsesDataCollected();
800 while (!dataCollected) {
801 usesNodes = new ArrayList<>(module.getAllUsesNodes());
802 for (UsesNodeBuilder usesNode : usesNodes) {
803 if (!usesNode.isDataCollected()) {
804 if (usesNode.getGroupingBuilder() == null) {
805 GroupingUtils.collectUsesDataFromContext(usesNode);
807 GroupingUtils.collectUsesData(usesNode);
811 dataCollected = module.isAllUsesDataCollected();
816 // new cycle is must because in collecting data process new uses could
818 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
819 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
820 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
821 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
825 for (UsesNodeBuilder usesNode : allModulesUses) {
826 GroupingUtils.updateUsesParent(usesNode);
827 GroupingUtils.performRefine(usesNode);
829 for (UsesNodeBuilder usesNode : allModulesUses) {
830 GroupingUtils.fixUsesNodesPath(usesNode);
834 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
835 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
836 QName nodeType = usnb.getNodeType();
838 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
840 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
841 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
842 usnb.setNodeType(extension.getQName());
843 usnb.setExtensionBuilder(extension);
847 } catch (YangParseException e) {
848 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
849 + ": no such extension definition found.");
854 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
855 final ModuleBuilder module, final SchemaContext context) {
856 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
857 QName nodeType = usnb.getNodeType();
859 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
860 nodeType.getPrefix(), usnb.getLine());
862 if (dependentModuleBuilder == null) {
863 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
865 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
866 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
867 usnb.setNodeType(new QName(e.getQName().getNamespace(),e.getQName().getRevision() , nodeType.getPrefix(), e.getQName().getLocalName()));
868 usnb.setExtensionDefinition(e);
873 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
874 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
875 usnb.setExtensionBuilder(extension);
881 } catch (YangParseException e) {
882 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
883 + ": no such extension definition found.");
890 * Traverse through modules and resolve their deviation statements.
895 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
896 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
897 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
898 ModuleBuilder b = inner.getValue();
899 resolveDeviation(modules, b);
905 * Traverse through module and resolve its deviation statements.
910 * module in which resolve deviations
912 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
913 for (DeviationBuilder dev : module.getDeviations()) {
914 int line = dev.getLine();
915 SchemaPath targetPath = dev.getTargetPath();
916 List<QName> path = targetPath.getPath();
917 QName q0 = path.get(0);
918 String prefix = q0.getPrefix();
919 if (prefix == null) {
920 prefix = module.getPrefix();
923 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
924 processDeviation(dev, dependentModuleBuilder, path, module);
929 * Traverse through modules and resolve their deviation statements with
935 * already resolved context
937 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
938 final SchemaContext context) {
939 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
940 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
941 ModuleBuilder b = inner.getValue();
942 resolveDeviationWithContext(modules, b, context);
948 * Traverse through module and resolve its deviation statements with given
954 * module in which resolve deviations
956 * already resolved context
958 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
959 final ModuleBuilder module, final SchemaContext context) {
960 for (DeviationBuilder dev : module.getDeviations()) {
961 int line = dev.getLine();
962 SchemaPath targetPath = dev.getTargetPath();
963 List<QName> path = targetPath.getPath();
964 QName q0 = path.get(0);
965 String prefix = q0.getPrefix();
966 if (prefix == null) {
967 prefix = module.getPrefix();
971 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
972 if (dependentModuleBuilder == null) {
973 Module dependentModule = findModuleFromContext(context, module, prefix, line);
974 Object currentParent = dependentModule;
976 for (int i = 0; i < path.size(); i++) {
977 if (currentParent == null) {
978 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
980 QName q = path.get(i);
981 name = q.getLocalName();
982 if (currentParent instanceof DataNodeContainer) {
983 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
987 if (currentParent == null) {
988 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
990 if (currentParent instanceof SchemaNode) {
991 dev.setTargetPath(((SchemaNode) currentParent).getPath());
995 processDeviation(dev, dependentModuleBuilder, path, module);
1001 * Correct deviation target path in deviation builder.
1005 * @param dependentModuleBuilder
1006 * module containing deviation target
1008 * current deviation target path
1012 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1013 final List<QName> path, final ModuleBuilder module) {
1014 final int line = dev.getLine();
1015 Builder currentParent = dependentModuleBuilder;
1017 for (int i = 0; i < path.size(); i++) {
1018 if (currentParent == null) {
1019 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1021 QName q = path.get(i);
1022 String name = q.getLocalName();
1023 if (currentParent instanceof DataNodeContainerBuilder) {
1024 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1028 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1029 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1031 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());