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.LinkedHashMap;
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.AnyXmlSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
42 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
44 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.Module;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
50 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
52 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
53 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
54 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
55 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
56 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
57 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
58 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
59 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
60 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
61 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
62 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
63 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
64 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
65 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
66 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
67 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
68 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
69 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
70 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
71 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
72 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
73 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
74 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
75 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
76 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
77 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
81 import com.google.common.collect.Lists;
82 import com.google.common.collect.Maps;
83 import com.google.common.collect.Sets;
85 public final class YangParserImpl implements YangModelParser {
86 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
89 public Set<Module> parseYangModels(final List<File> yangFiles) {
90 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
94 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
96 throw new YangParseException("Not yet implemented");
97 // if (yangFiles != null) {
98 // final Map<InputStream, File> inputStreams = Maps.newHashMap();
100 // for (final File yangFile : yangFiles) {
102 // inputStreams.put(new FileInputStream(yangFile), yangFile);
103 // } catch (FileNotFoundException e) {
104 // LOG.warn("Exception while reading yang file: " + yangFile.getName(),
109 // Map<ModuleBuilder, InputStream> builderToStreamMap =
110 // Maps.newHashMap();
112 // final Map<String, TreeMap<Date, ModuleBuilder>> modules =
113 // resolveModuleBuilders(
114 // Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
116 // for (InputStream is : inputStreams.keySet()) {
119 // } catch (IOException e) {
120 // LOG.debug("Failed to close stream.");
124 // return new LinkedHashSet<Module>(buildWithContext(modules,
125 // context).values());
127 // return Collections.emptySet();
131 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
132 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
136 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
138 throw new YangParseException("Not yet implemented");
139 // if (yangModelStreams != null) {
140 // Map<ModuleBuilder, InputStream> builderToStreamMap =
141 // Maps.newHashMap();
142 // final Map<String, TreeMap<Date, ModuleBuilder>> modules =
143 // resolveModuleBuildersWithContext(
144 // yangModelStreams, builderToStreamMap, context);
145 // return new LinkedHashSet<Module>(buildWithContext(modules,
146 // context).values());
148 // return Collections.emptySet();
152 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
153 if (yangFiles != null) {
154 final Map<InputStream, File> inputStreams = Maps.newHashMap();
156 for (final File yangFile : yangFiles) {
158 inputStreams.put(new FileInputStream(yangFile), yangFile);
159 } catch (FileNotFoundException e) {
160 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
164 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
165 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
166 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
168 for (InputStream is : inputStreams.keySet()) {
171 } catch (IOException e) {
172 LOG.debug("Failed to close stream.");
176 Map<File, Module> retVal = Maps.newLinkedHashMap();
177 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
179 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
180 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
181 builderToModule.getValue());
186 return Collections.emptyMap();
190 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
191 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
193 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
195 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
196 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
198 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
199 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
205 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
206 return new SchemaContextImpl(modules);
209 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
210 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
212 final ParseTreeWalker walker = new ParseTreeWalker();
213 final List<ParseTree> trees = parseStreams(inputStreams);
214 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
217 new YangModelBasicValidator(walker).validate(trees);
219 YangParserListenerImpl yangModelParser = null;
220 for (int i = 0; i < trees.size(); i++) {
221 yangModelParser = new YangParserListenerImpl();
222 walker.walk(yangModelParser, trees.get(i));
223 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
225 // We expect the order of trees and streams has to be the same
226 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
227 builders[i] = moduleBuilder;
232 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
233 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
234 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
237 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
238 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
239 final SchemaContext context) {
240 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
242 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
243 // of items stored in map.
244 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
246 // module dependency graph sorted
247 List<ModuleBuilder> sorted = null;
248 if (context == null) {
249 sorted = ModuleDependencySort.sort(builders);
251 sorted = ModuleDependencySort.sortWithContext(context, builders);
254 for (final ModuleBuilder builder : sorted) {
255 if (builder == null) {
258 final String builderName = builder.getName();
259 Date builderRevision = builder.getRevision();
260 if (builderRevision == null) {
261 builderRevision = new Date(0L);
263 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
264 if (builderByRevision == null) {
265 builderByRevision = new TreeMap<Date, ModuleBuilder>();
267 builderByRevision.put(builderRevision, builder);
268 modules.put(builderName, builderByRevision);
273 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
274 final List<ParseTree> trees = new ArrayList<ParseTree>();
275 for (InputStream yangStream : yangStreams) {
276 trees.add(parseStream(yangStream));
281 private ParseTree parseStream(final InputStream yangStream) {
282 ParseTree result = null;
284 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
285 final YangLexer lexer = new YangLexer(input);
286 final CommonTokenStream tokens = new CommonTokenStream(lexer);
287 final YangParser parser = new YangParser(tokens);
288 parser.removeErrorListeners();
289 parser.addErrorListener(new YangErrorListener());
291 result = parser.yang();
292 } catch (IOException e) {
293 LOG.warn("Exception while reading yang file: " + yangStream, e);
298 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
299 // fix unresolved nodes
300 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
301 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
302 final ModuleBuilder moduleBuilder = childEntry.getValue();
303 fixUnresolvedNodes(modules, moduleBuilder);
306 resolveAugments(modules);
307 finishResolvingUses(modules);
308 resolveDeviations(modules);
311 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
312 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
313 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
314 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
315 final ModuleBuilder moduleBuilder = childEntry.getValue();
316 final Module module = moduleBuilder.build();
317 modulesByRevision.put(childEntry.getKey(), module);
318 result.put(moduleBuilder, module);
324 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
325 SchemaContext context) {
326 // fix unresolved nodes
327 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
328 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
329 final ModuleBuilder moduleBuilder = childEntry.getValue();
330 fixUnresolvedNodesWithContext(modules, moduleBuilder, context);
333 resolveAugmentsWithContext(modules, context);
334 resolveDeviationsWithContext(modules, context);
337 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
338 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
339 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
340 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
341 final ModuleBuilder moduleBuilder = childEntry.getValue();
342 final Module module = moduleBuilder.build();
343 modulesByRevision.put(childEntry.getKey(), module);
344 result.put(moduleBuilder, module);
350 private void fixUnresolvedNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder builder) {
351 resolveDirtyNodes(modules, builder);
352 resolveIdentities(modules, builder);
353 resolveUsesNodes(modules, builder);
354 resolveUnknownNodes(modules, builder);
357 private void fixUnresolvedNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
358 final ModuleBuilder builder, final SchemaContext context) {
359 resolveDirtyNodesWithContext(modules, builder, context);
360 resolveIdentitiesWithContext(modules, builder, context);
361 resolveUsesNodesWithContext(modules, builder, context);
362 resolveUnknownNodesWithContext(modules, builder, context);
366 * Search for dirty nodes (node which contains UnknownType) and resolve
370 * all available modules
374 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
375 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
376 if (!dirtyNodes.isEmpty()) {
377 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
378 if (nodeToResolve instanceof UnionTypeBuilder) {
379 // special handling for union types
380 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
381 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
382 // special handling for identityref types
383 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
384 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
386 resolveType(nodeToResolve, modules, module);
392 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
393 final ModuleBuilder module, SchemaContext context) {
394 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
395 if (!dirtyNodes.isEmpty()) {
396 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
397 if (nodeToResolve instanceof UnionTypeBuilder) {
398 // special handling for union types
399 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
400 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
401 // special handling for identityref types
402 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
403 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
405 resolveTypeWithContext(nodeToResolve, modules, module, context);
412 * Go through all augment definitions and perform augmentation. It is
413 * expected that modules are already sorted by their dependencies.
418 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
419 // collect augments from all loaded modules
420 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
421 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
422 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
423 allAugments.addAll(inner.getValue().getAllAugments());
427 for (int i = 0; i < allAugments.size(); i++) {
429 final AugmentationSchemaBuilder augment = allAugments.get(i);
430 // create collection of others
431 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
432 others.remove(augment);
435 boolean resolved = resolveAugment(modules, augment);
436 // while not resolved
438 while (!(resolved) && j < others.size()) {
439 // try to resolve next augment
440 resolveAugment(modules, others.get(j));
441 // then try to resolve first again
442 resolved = resolveAugment(modules, augment);
448 throw new YangParseException(augment.getModuleName(), augment.getLine(),
449 "Error in augment parsing: failed to find augment target");
455 * Search for augment target and perform augmentation.
459 * @param augmentBuilder
461 * @return true if target node found, false otherwise
463 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
464 final AugmentationSchemaBuilder augmentBuilder) {
465 if (augmentBuilder.isResolved()) {
469 int line = augmentBuilder.getLine();
470 ModuleBuilder module = getParentModule(augmentBuilder);
471 List<QName> path = augmentBuilder.getTargetPath().getPath();
472 Builder augmentParent = augmentBuilder.getParent();
473 boolean isUsesAugment = false;
475 Builder firstNodeParent = null;
476 if (augmentParent instanceof ModuleBuilder) {
477 // if augment is defined under module, parent of first node is
479 final QName firstNameInPath = path.get(0);
480 String prefix = firstNameInPath.getPrefix();
481 if (prefix == null) {
482 prefix = module.getPrefix();
484 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
485 } else if (augmentParent instanceof UsesNodeBuilder) {
486 // if augment is defined under uses, parent of first node is uses
488 isUsesAugment = true;
489 firstNodeParent = augmentParent.getParent();
491 // augment can be defined only under module or uses
492 throw new YangParseException(augmentBuilder.getModuleName(), line,
493 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
496 return processAugmentation(augmentBuilder, firstNodeParent, path, isUsesAugment);
500 * Go through all augment definitions and resolve them. This method works in
501 * same way as {@link #resolveAugments(Map)} except that if target node is
502 * not found in loaded modules, it search for target node in given context.
507 * SchemaContext containing already resolved modules
509 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
510 final SchemaContext context) {
511 // collect augments from all loaded modules
512 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
513 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
514 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
515 allAugments.addAll(inner.getValue().getAllAugments());
519 for (int i = 0; i < allAugments.size(); i++) {
520 // pick augment from list
521 final AugmentationSchemaBuilder augment = allAugments.get(i);
523 boolean resolved = resolveAugmentWithContext(modules, augment, context);
524 // while not resolved
526 while (!(resolved) && j < allAugments.size()) {
527 // try to resolve next augment
528 resolveAugmentWithContext(modules, allAugments.get(j), context);
529 // then try to resolve first again
530 resolved = resolveAugmentWithContext(modules, augment, context);
535 throw new YangParseException(augment.getModuleName(), augment.getLine(),
536 "Error in augment parsing: failed to find augment target");
542 * Search for augment target and perform augmentation.
546 * @param augmentBuilder
549 * SchemaContext containing already resolved modules
550 * @return true if target node found, false otherwise
552 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
553 final AugmentationSchemaBuilder augmentBuilder, final SchemaContext context) {
554 if (augmentBuilder.isResolved()) {
557 int line = augmentBuilder.getLine();
558 ModuleBuilder module = getParentModule(augmentBuilder);
559 List<QName> path = augmentBuilder.getTargetPath().getPath();
560 final QName firstNameInPath = path.get(0);
561 String prefix = firstNameInPath.getPrefix();
562 if (prefix == null) {
563 prefix = module.getPrefix();
565 Builder augmentParent = augmentBuilder.getParent();
566 Builder currentParent = null;
567 boolean isUsesAugment = false;
569 if (augmentParent instanceof ModuleBuilder) {
570 // if augment is defined under module, first parent is target module
571 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
572 } else if (augmentParent instanceof UsesNodeBuilder) {
573 // if augment is defined under uses, first parent is uses parent
574 isUsesAugment = true;
575 currentParent = augmentParent.getParent();
577 // augment can be defined only under module or uses
578 throw new YangParseException(augmentBuilder.getModuleName(), augmentBuilder.getLine(),
579 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
582 if (currentParent == null) {
583 return processAugmentationOnContext(augmentBuilder, path, module, prefix, context);
585 return processAugmentation(augmentBuilder, currentParent, path, isUsesAugment);
590 * Go through identity statements defined in current module and resolve
591 * their 'base' statement if present.
596 * module being resolved
598 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
599 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
600 for (IdentitySchemaNodeBuilder identity : identities) {
601 final String baseIdentityName = identity.getBaseIdentityName();
602 if (baseIdentityName != null) {
603 String baseIdentityPrefix = null;
604 String baseIdentityLocalName = null;
605 if (baseIdentityName.contains(":")) {
606 final String[] splitted = baseIdentityName.split(":");
607 baseIdentityPrefix = splitted[0];
608 baseIdentityLocalName = splitted[1];
610 baseIdentityPrefix = module.getPrefix();
611 baseIdentityLocalName = baseIdentityName;
613 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
616 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
617 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
618 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
619 identity.setBaseIdentity(idBuilder);
627 * Go through identity statements defined in current module and resolve
628 * their 'base' statement. Method tries to find base identity in given
629 * modules. If base identity is not found, method will search it in context.
636 * SchemaContext containing already resolved modules
638 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
639 final ModuleBuilder module, final SchemaContext context) {
640 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
641 for (IdentitySchemaNodeBuilder identity : identities) {
642 final String baseIdentityName = identity.getBaseIdentityName();
643 if (baseIdentityName != null) {
644 String baseIdentityPrefix = null;
645 String baseIdentityLocalName = null;
646 if (baseIdentityName.contains(":")) {
647 final String[] splitted = baseIdentityName.split(":");
648 baseIdentityPrefix = splitted[0];
649 baseIdentityLocalName = splitted[1];
651 baseIdentityPrefix = module.getPrefix();
652 baseIdentityLocalName = baseIdentityName;
654 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
655 baseIdentityPrefix, identity.getLine());
657 if (dependentModuleBuilder == null) {
658 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
660 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
661 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
662 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
663 identity.setBaseIdentity(idNode);
667 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
669 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
670 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
671 identity.setBaseIdentity(idBuilder);
680 * Go through uses statements defined in current module and resolve their
686 * module being resolved
688 private void resolveUsesNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
689 final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
690 List<UsesNodeBuilder> collection = new ArrayList<>(module.getAllUsesNodes());
691 boolean usesDataLoaded = module.allUsesLoadDone();
692 while (!usesDataLoaded) {
693 for (UsesNodeBuilder usesNode : collection) {
694 if (!usesNode.isLoadDone()) {
695 final GroupingBuilder targetGrouping = GroupingUtils.getTargetGroupingFromModules(usesNode,
697 usesNode.setGroupingPath(targetGrouping.getPath());
698 // load uses target nodes in uses
699 GroupingUtils.loadTargetGroupingData(usesNode, targetGrouping);
702 collection = new ArrayList<>(module.getAllUsesNodes());
703 usesDataLoaded = module.allUsesLoadDone();
706 for (UsesNodeBuilder usesNode : allModuleUses) {
707 final GroupingBuilder targetGrouping = GroupingUtils
708 .getTargetGroupingFromModules(usesNode, modules, module);
709 // load uses target uses nodes in uses
710 GroupingUtils.loadTargetGroupingUses(usesNode, targetGrouping);
714 private void finishResolvingUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
715 final List<UsesNodeBuilder> alluses = new ArrayList<>();
716 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
717 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
718 alluses.addAll(inner.getValue().getAllUsesNodes());
721 for (UsesNodeBuilder usesNode : alluses) {
722 ParserUtils.processUsesNode(usesNode);
724 for (UsesNodeBuilder usesNode : alluses) {
725 ParserUtils.performRefine(usesNode);
726 ParserUtils.updateUsesParent(usesNode, usesNode.getParent());
728 for (UsesNodeBuilder usesNode : alluses) {
729 ParserUtils.fixUsesNodesPath(usesNode);
734 * Tries to search target grouping in given modules and resolve refine
735 * nodes. If grouping is not found in modules, method tries to find it in
736 * modules from context.
743 * SchemaContext containing already resolved modules
745 private void resolveUsesNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
746 final ModuleBuilder module, final SchemaContext context) {
747 final List<UsesNodeBuilder> allModuleUses = module.getAllUsesNodes();
748 for (UsesNodeBuilder usesNode : allModuleUses) {
749 // process uses operation
750 final GroupingBuilder targetGrouping = GroupingUtils
751 .getTargetGroupingFromModules(usesNode, modules, module);
752 if (targetGrouping == null) {
755 usesNode.setGroupingPath(targetGrouping.getPath());
756 GroupingUtils.loadTargetGroupingData(usesNode, targetGrouping);
759 for (UsesNodeBuilder usesNode : allModuleUses) {
760 final GroupingBuilder targetGrouping = GroupingUtils
761 .getTargetGroupingFromModules(usesNode, modules, module);
762 if (targetGrouping == null) {
765 GroupingUtils.loadTargetGroupingUses(usesNode, targetGrouping);
770 // TODO use in implementation
771 private void processUsesNode(final UsesNodeBuilder usesNode, final GroupingDefinition targetGrouping) {
772 final String moduleName = usesNode.getModuleName();
773 final int line = usesNode.getLine();
774 DataNodeContainerBuilder parent = usesNode.getParent();
775 URI namespace = null;
776 Date revision = null;
777 String prefix = null;
778 if (parent instanceof ModuleBuilder) {
779 ModuleBuilder m = (ModuleBuilder) parent;
780 namespace = m.getNamespace();
781 revision = m.getRevision();
782 prefix = m.getPrefix();
784 QName parentQName = parent.getQName();
785 namespace = parentQName.getNamespace();
786 revision = parentQName.getRevision();
787 prefix = parentQName.getPrefix();
789 SchemaPath parentPath = parent.getPath();
791 final Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
792 for (DataSchemaNode child : targetGrouping.getChildNodes()) {
794 DataSchemaNodeBuilder newChild = null;
795 QName newQName = new QName(namespace, revision, prefix, child.getQName().getLocalName());
796 if (child instanceof AnyXmlSchemaNode) {
797 newChild = createAnyXml((AnyXmlSchemaNode) child, newQName, moduleName, line);
798 } else if (child instanceof ChoiceNode) {
799 newChild = createChoice((ChoiceNode) child, newQName, moduleName, line);
800 } else if (child instanceof ContainerSchemaNode) {
801 newChild = createContainer((ContainerSchemaNode) child, newQName, moduleName, line);
802 } else if (child instanceof LeafListSchemaNode) {
803 newChild = createLeafList((LeafListSchemaNode) child, newQName, moduleName, line);
804 } else if (child instanceof LeafSchemaNode) {
805 newChild = createLeafBuilder((LeafSchemaNode) child, newQName, moduleName, line);
806 } else if (child instanceof ListSchemaNode) {
807 newChild = createList((ListSchemaNode) child, newQName, moduleName, line);
810 if (newChild == null) {
811 throw new YangParseException(moduleName, line,
812 "Unknown member of target grouping while resolving uses node.");
814 if (newChild instanceof GroupingMember) {
815 ((GroupingMember) newChild).setAddedByUses(true);
818 newChild.setPath(createSchemaPath(parentPath, newQName));
819 newChildren.add(newChild);
822 usesNode.getFinalChildren().addAll(newChildren);
824 final Set<GroupingBuilder> newGroupings = new HashSet<>();
825 for (GroupingDefinition g : targetGrouping.getGroupings()) {
826 QName newQName = new QName(namespace, revision, prefix, g.getQName().getLocalName());
827 GroupingBuilder newGrouping = createGrouping(g, newQName, moduleName, line);
828 newGrouping.setAddedByUses(true);
829 newGrouping.setPath(createSchemaPath(parentPath, newQName));
830 newGroupings.add(newGrouping);
832 usesNode.getFinalGroupings().addAll(newGroupings);
834 final Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
835 for (TypeDefinition<?> td : targetGrouping.getTypeDefinitions()) {
836 QName newQName = new QName(namespace, revision, prefix, td.getQName().getLocalName());
837 TypeDefinitionBuilder newType = createTypedef((ExtendedType) td, newQName, moduleName, line);
838 newType.setAddedByUses(true);
839 newType.setPath(createSchemaPath(parentPath, newQName));
840 newTypedefs.add(newType);
842 usesNode.getFinalTypedefs().addAll(newTypedefs);
844 final List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
845 for (UnknownSchemaNode un : targetGrouping.getUnknownSchemaNodes()) {
846 QName newQName = new QName(namespace, revision, prefix, un.getQName().getLocalName());
847 UnknownSchemaNodeBuilder newNode = createUnknownSchemaNode(un, newQName, moduleName, line);
848 newNode.setAddedByUses(true);
849 newNode.setPath(createSchemaPath(parentPath, newQName));
850 newUnknownNodes.add(newNode);
852 usesNode.getFinalUnknownNodes().addAll(newUnknownNodes);
855 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
856 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
857 QName nodeType = usnb.getNodeType();
858 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
860 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
862 QName newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
863 nodeType.getPrefix(), nodeType.getLocalName());
864 usnb.setNodeType(newNodeType);
865 } catch (YangParseException e) {
866 LOG.debug(module.getName(), usnb.getLine(), "Failed to find unknown node type: " + nodeType);
872 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
873 final ModuleBuilder module, final SchemaContext context) {
874 for (UnknownSchemaNodeBuilder unknownNodeBuilder : module.getAllUnknownNodes()) {
875 QName nodeType = unknownNodeBuilder.getNodeType();
876 if (nodeType.getNamespace() == null || nodeType.getRevision() == null) {
878 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
879 nodeType.getPrefix(), unknownNodeBuilder.getLine());
881 QName newNodeType = null;
882 if (dependentModuleBuilder == null) {
883 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
884 unknownNodeBuilder.getLine());
885 newNodeType = new QName(dependentModule.getNamespace(), dependentModule.getRevision(),
886 nodeType.getPrefix(), nodeType.getLocalName());
888 newNodeType = new QName(dependentModuleBuilder.getNamespace(),
889 dependentModuleBuilder.getRevision(), nodeType.getPrefix(), nodeType.getLocalName());
892 unknownNodeBuilder.setNodeType(newNodeType);
893 } catch (YangParseException e) {
894 LOG.debug(module.getName(), unknownNodeBuilder.getLine(), "Failed to find unknown node type: "
902 * Traverse through modules and resolve their deviation statements.
907 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
908 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
909 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
910 ModuleBuilder b = inner.getValue();
911 resolveDeviation(modules, b);
917 * Traverse through module and resolve its deviation statements.
922 * module in which resolve deviations
924 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
925 for (DeviationBuilder dev : module.getDeviations()) {
926 int line = dev.getLine();
927 SchemaPath targetPath = dev.getTargetPath();
928 List<QName> path = targetPath.getPath();
929 QName q0 = path.get(0);
930 String prefix = q0.getPrefix();
931 if (prefix == null) {
932 prefix = module.getPrefix();
935 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
936 processDeviation(dev, dependentModuleBuilder, path, module);
941 * Traverse through modules and resolve their deviation statements with
947 * already resolved context
949 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
950 final SchemaContext context) {
951 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
952 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
953 ModuleBuilder b = inner.getValue();
954 resolveDeviationWithContext(modules, b, context);
960 * Traverse through module and resolve its deviation statements with given
966 * module in which resolve deviations
968 * already resolved context
970 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
971 final ModuleBuilder module, final SchemaContext context) {
972 for (DeviationBuilder dev : module.getDeviations()) {
973 int line = dev.getLine();
974 SchemaPath targetPath = dev.getTargetPath();
975 List<QName> path = targetPath.getPath();
976 QName q0 = path.get(0);
977 String prefix = q0.getPrefix();
978 if (prefix == null) {
979 prefix = module.getPrefix();
983 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
984 if (dependentModuleBuilder == null) {
985 Module dependentModule = findModuleFromContext(context, module, prefix, line);
986 Object currentParent = dependentModule;
988 for (int i = 0; i < path.size(); i++) {
989 if (currentParent == null) {
990 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
992 QName q = path.get(i);
993 name = q.getLocalName();
994 if (currentParent instanceof DataNodeContainer) {
995 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
999 if (currentParent == null) {
1000 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1002 if (currentParent instanceof SchemaNode) {
1003 dev.setTargetPath(((SchemaNode) currentParent).getPath());
1007 processDeviation(dev, dependentModuleBuilder, path, module);
1013 * Correct deviation target path in deviation builder.
1017 * @param dependentModuleBuilder
1018 * module containing deviation target
1020 * current deviation target path
1024 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
1025 final List<QName> path, final ModuleBuilder module) {
1026 final int line = dev.getLine();
1027 Builder currentParent = dependentModuleBuilder;
1029 for (int i = 0; i < path.size(); i++) {
1030 if (currentParent == null) {
1031 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1033 QName q = path.get(i);
1034 String name = q.getLocalName();
1035 if (currentParent instanceof DataNodeContainerBuilder) {
1036 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
1040 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
1041 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
1043 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());