2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
8 package org.opendaylight.yangtools.yang.parser.impl;
\r
10 import static org.opendaylight.yangtools.yang.parser.util.ParserUtils.*;
\r
11 import static org.opendaylight.yangtools.yang.parser.util.TypeUtils.*;
\r
13 import java.io.File;
\r
14 import java.io.FileInputStream;
\r
15 import java.io.FileNotFoundException;
\r
16 import java.io.IOException;
\r
17 import java.io.InputStream;
\r
18 import java.util.ArrayList;
\r
19 import java.util.Collections;
\r
20 import java.util.Date;
\r
21 import java.util.HashMap;
\r
22 import java.util.LinkedHashMap;
\r
23 import java.util.LinkedHashSet;
\r
24 import java.util.List;
\r
25 import java.util.Map;
\r
26 import java.util.Map.Entry;
\r
27 import java.util.Set;
\r
28 import java.util.TreeMap;
\r
30 import org.antlr.v4.runtime.ANTLRInputStream;
\r
31 import org.antlr.v4.runtime.CommonTokenStream;
\r
32 import org.antlr.v4.runtime.tree.ParseTree;
\r
33 import org.antlr.v4.runtime.tree.ParseTreeWalker;
\r
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangLexer;
\r
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
\r
36 import org.opendaylight.yangtools.yang.common.QName;
\r
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
\r
38 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
\r
39 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
\r
40 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
\r
41 import org.opendaylight.yangtools.yang.model.api.Module;
\r
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
\r
43 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
\r
44 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
\r
45 import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
\r
46 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
\r
47 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
\r
48 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
\r
49 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
\r
50 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
\r
51 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
\r
52 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
\r
53 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
\r
54 import org.opendaylight.yangtools.yang.parser.builder.impl.DeviationBuilder;
\r
55 import org.opendaylight.yangtools.yang.parser.builder.impl.ExtensionBuilder;
\r
56 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
\r
57 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
\r
58 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
\r
59 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
\r
60 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
\r
61 import org.opendaylight.yangtools.yang.parser.util.GroupingUtils;
\r
62 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
\r
63 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
\r
64 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
\r
65 import org.opendaylight.yangtools.yang.validator.YangModelBasicValidator;
\r
66 import org.slf4j.Logger;
\r
67 import org.slf4j.LoggerFactory;
\r
69 import com.google.common.collect.Lists;
\r
70 import com.google.common.collect.Maps;
\r
71 import com.google.common.collect.Sets;
\r
73 public final class YangParserImpl implements YangModelParser {
\r
74 private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
\r
77 public Set<Module> parseYangModels(final List<File> yangFiles) {
\r
78 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
\r
82 public Set<Module> parseYangModels(final List<File> yangFiles, final SchemaContext context) {
\r
83 if (yangFiles != null) {
\r
84 final Map<InputStream, File> inputStreams = Maps.newHashMap();
\r
86 for (final File yangFile : yangFiles) {
\r
88 inputStreams.put(new FileInputStream(yangFile), yangFile);
\r
89 } catch (FileNotFoundException e) {
\r
90 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
\r
94 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
\r
96 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
\r
97 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
\r
99 for (InputStream is : inputStreams.keySet()) {
\r
102 } catch (IOException e) {
\r
103 LOG.debug("Failed to close stream.");
\r
107 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
\r
109 return Collections.emptySet();
\r
113 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams) {
\r
114 return Sets.newHashSet(parseYangModelsFromStreamsMapped(yangModelStreams).values());
\r
118 public Set<Module> parseYangModelsFromStreams(final List<InputStream> yangModelStreams, SchemaContext context) {
\r
119 if (yangModelStreams != null) {
\r
120 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
\r
121 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuildersWithContext(
\r
122 yangModelStreams, builderToStreamMap, context);
\r
123 return new LinkedHashSet<Module>(buildWithContext(modules, context).values());
\r
125 return Collections.emptySet();
\r
129 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
\r
130 if (yangFiles != null) {
\r
131 final Map<InputStream, File> inputStreams = Maps.newHashMap();
\r
133 for (final File yangFile : yangFiles) {
\r
135 inputStreams.put(new FileInputStream(yangFile), yangFile);
\r
136 } catch (FileNotFoundException e) {
\r
137 LOG.warn("Exception while reading yang file: " + yangFile.getName(), e);
\r
141 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
\r
142 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
\r
143 Lists.newArrayList(inputStreams.keySet()), builderToStreamMap);
\r
145 for (InputStream is : inputStreams.keySet()) {
\r
148 } catch (IOException e) {
\r
149 LOG.debug("Failed to close stream.");
\r
153 Map<File, Module> retVal = Maps.newLinkedHashMap();
\r
154 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
\r
156 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
\r
157 retVal.put(inputStreams.get(builderToStreamMap.get(builderToModule.getKey())),
\r
158 builderToModule.getValue());
\r
163 return Collections.emptyMap();
\r
167 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(final List<InputStream> yangModelStreams) {
\r
168 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
\r
170 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams,
\r
171 builderToStreamMap);
\r
172 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
\r
173 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
\r
175 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap.entrySet()) {
\r
176 retVal.put(builderToStreamMap.get(builderToModule.getKey()), builderToModule.getValue());
\r
182 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
\r
183 return new SchemaContextImpl(modules);
\r
186 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
\r
187 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
\r
189 final ParseTreeWalker walker = new ParseTreeWalker();
\r
190 final List<ParseTree> trees = parseStreams(inputStreams);
\r
191 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
\r
194 new YangModelBasicValidator(walker).validate(trees);
\r
196 YangParserListenerImpl yangModelParser = null;
\r
197 for (int i = 0; i < trees.size(); i++) {
\r
198 yangModelParser = new YangParserListenerImpl();
\r
199 walker.walk(yangModelParser, trees.get(i));
\r
200 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
\r
202 // We expect the order of trees and streams has to be the same
\r
203 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
\r
204 builders[i] = moduleBuilder;
\r
209 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(final List<InputStream> yangFileStreams,
\r
210 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
\r
211 return resolveModuleBuildersWithContext(yangFileStreams, streamToBuilderMap, null);
\r
214 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuildersWithContext(
\r
215 final List<InputStream> yangFileStreams, final Map<ModuleBuilder, InputStream> streamToBuilderMap,
\r
216 final SchemaContext context) {
\r
217 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams, streamToBuilderMap);
\r
219 // LinkedHashMap must be used to preserve order
\r
220 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
\r
222 // module dependency graph sorted
\r
223 List<ModuleBuilder> sorted = null;
\r
224 if (context == null) {
\r
225 sorted = ModuleDependencySort.sort(builders);
\r
227 sorted = ModuleDependencySort.sortWithContext(context, builders);
\r
230 for (final ModuleBuilder builder : sorted) {
\r
231 if (builder == null) {
\r
234 final String builderName = builder.getName();
\r
235 Date builderRevision = builder.getRevision();
\r
236 if (builderRevision == null) {
\r
237 builderRevision = new Date(0L);
\r
239 TreeMap<Date, ModuleBuilder> builderByRevision = modules.get(builderName);
\r
240 if (builderByRevision == null) {
\r
241 builderByRevision = new TreeMap<Date, ModuleBuilder>();
\r
243 builderByRevision.put(builderRevision, builder);
\r
244 modules.put(builderName, builderByRevision);
\r
249 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
\r
250 final List<ParseTree> trees = new ArrayList<ParseTree>();
\r
251 for (InputStream yangStream : yangStreams) {
\r
252 trees.add(parseStream(yangStream));
\r
257 private ParseTree parseStream(final InputStream yangStream) {
\r
258 ParseTree result = null;
\r
260 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
\r
261 final YangLexer lexer = new YangLexer(input);
\r
262 final CommonTokenStream tokens = new CommonTokenStream(lexer);
\r
263 final YangParser parser = new YangParser(tokens);
\r
264 parser.removeErrorListeners();
\r
265 parser.addErrorListener(new YangErrorListener());
\r
267 result = parser.yang();
\r
268 } catch (IOException e) {
\r
269 LOG.warn("Exception while reading yang file: " + yangStream, e);
\r
274 private Map<ModuleBuilder, Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
275 // fix unresolved nodes
\r
276 findUsesTargets(modules, null);
\r
277 resolveDirtyNodes(modules);
\r
278 resolveAugments(modules);
\r
279 resolveUses(modules);
\r
280 resolveDeviations(modules);
\r
283 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
\r
284 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
285 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
\r
286 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
\r
287 final ModuleBuilder moduleBuilder = childEntry.getValue();
\r
288 final Module module = moduleBuilder.build();
\r
289 modulesByRevision.put(childEntry.getKey(), module);
\r
290 result.put(moduleBuilder, module);
\r
296 private Map<ModuleBuilder, Module> buildWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
297 final SchemaContext context) {
\r
298 // fix unresolved nodes
\r
299 findUsesTargets(modules, context);
\r
300 resolvedDirtyNodesWithContext(modules, context);
\r
301 resolveAugmentsWithContext(modules, context);
\r
302 resolveUsesWithContext(modules, context);
\r
303 resolveDeviationsWithContext(modules, context);
\r
306 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
\r
307 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
308 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
\r
309 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
\r
310 final ModuleBuilder moduleBuilder = childEntry.getValue();
\r
311 final Module module = moduleBuilder.build();
\r
312 modulesByRevision.put(childEntry.getKey(), module);
\r
313 result.put(moduleBuilder, module);
\r
319 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
320 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
321 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
\r
322 final ModuleBuilder module = childEntry.getValue();
\r
323 resolveDirtyNodes(modules, module);
\r
324 resolveIdentities(modules, module);
\r
325 resolveUnknownNodes(modules, module);
\r
330 private void resolvedDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
331 final SchemaContext context) {
\r
332 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
333 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
\r
334 final ModuleBuilder module = childEntry.getValue();
\r
335 resolveDirtyNodesWithContext(modules, module, context);
\r
336 resolveIdentitiesWithContext(modules, module, context);
\r
337 resolveUnknownNodesWithContext(modules, module, context);
\r
343 * Search for dirty nodes (node which contains UnknownType) and resolve
\r
347 * all available modules
\r
351 private void resolveDirtyNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
\r
352 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
\r
353 if (!dirtyNodes.isEmpty()) {
\r
354 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
\r
355 if (nodeToResolve instanceof UnionTypeBuilder) {
\r
356 // special handling for union types
\r
357 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules, module);
\r
358 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
\r
359 // special handling for identityref types
\r
360 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
\r
361 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
\r
363 resolveType(nodeToResolve, modules, module);
\r
369 private void resolveDirtyNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
370 final ModuleBuilder module, SchemaContext context) {
\r
371 final Set<TypeAwareBuilder> dirtyNodes = module.getDirtyNodes();
\r
372 if (!dirtyNodes.isEmpty()) {
\r
373 for (TypeAwareBuilder nodeToResolve : dirtyNodes) {
\r
374 if (nodeToResolve instanceof UnionTypeBuilder) {
\r
375 // special handling for union types
\r
376 resolveTypeUnionWithContext((UnionTypeBuilder) nodeToResolve, modules, module, context);
\r
377 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
\r
378 // special handling for identityref types
\r
379 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve.getTypedef();
\r
380 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref), idref.getPath()));
\r
382 resolveTypeWithContext(nodeToResolve, modules, module, context);
\r
389 * Go through all augment definitions and perform augmentation. It is
\r
390 * expected that modules are already sorted by their dependencies.
\r
393 * all loaded modules
\r
395 private void resolveAugments(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
396 // collect augments from all loaded modules
\r
397 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
\r
398 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
399 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
400 allAugments.addAll(inner.getValue().getAllAugments());
\r
404 for (int i = 0; i < allAugments.size(); i++) {
\r
405 // pick one augment
\r
406 final AugmentationSchemaBuilder augment = allAugments.get(i);
\r
407 // create collection of others
\r
408 List<AugmentationSchemaBuilder> others = new ArrayList<>(allAugments);
\r
409 others.remove(augment);
\r
411 // try to resolve it
\r
412 boolean resolved = resolveAugment(modules, augment);
\r
413 // while not resolved
\r
415 while (!(resolved) && j < others.size()) {
\r
416 // try to resolve next augment
\r
417 resolveAugment(modules, others.get(j));
\r
418 // then try to resolve first again
\r
419 resolved = resolveAugment(modules, augment);
\r
425 throw new YangParseException(augment.getModuleName(), augment.getLine(),
\r
426 "Error in augment parsing: failed to find augment target");
\r
432 * Search for augment target and perform augmentation.
\r
435 * all loaded modules
\r
436 * @param augmentBuilder
\r
437 * augment to resolve
\r
438 * @return true if target node found, false otherwise
\r
440 private boolean resolveAugment(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
441 final AugmentationSchemaBuilder augmentBuilder) {
\r
442 if (augmentBuilder.isResolved()) {
\r
446 int line = augmentBuilder.getLine();
\r
447 ModuleBuilder module = getParentModule(augmentBuilder);
\r
448 List<QName> path = augmentBuilder.getTargetPath().getPath();
\r
449 Builder augmentParent = augmentBuilder.getParent();
\r
451 Builder firstNodeParent = null;
\r
452 if (augmentParent instanceof ModuleBuilder) {
\r
453 // if augment is defined under module, parent of first node is
\r
455 final QName firstNameInPath = path.get(0);
\r
456 String prefix = firstNameInPath.getPrefix();
\r
457 if (prefix == null) {
\r
458 prefix = module.getPrefix();
\r
460 firstNodeParent = findDependentModuleBuilder(modules, module, prefix, line);
\r
461 } else if (augmentParent instanceof UsesNodeBuilder) {
\r
462 firstNodeParent = augmentParent.getParent();
\r
464 // augment can be defined only under module or uses
\r
465 throw new YangParseException(augmentBuilder.getModuleName(), line,
\r
466 "Failed to parse augment: Unresolved parent of augment: " + augmentParent);
\r
469 return processAugmentation(augmentBuilder, firstNodeParent, path);
\r
473 * Go through all augment definitions and resolve them. This method works in
\r
474 * same way as {@link #resolveAugments(Map)} except that if target node is
\r
475 * not found in loaded modules, it search for target node in given context.
\r
478 * all loaded modules
\r
480 * SchemaContext containing already resolved modules
\r
482 private void resolveAugmentsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
483 final SchemaContext context) {
\r
484 // collect augments from all loaded modules
\r
485 final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
\r
486 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
487 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
488 allAugments.addAll(inner.getValue().getAllAugments());
\r
492 for (int i = 0; i < allAugments.size(); i++) {
\r
493 // pick augment from list
\r
494 final AugmentationSchemaBuilder augment = allAugments.get(i);
\r
495 // try to resolve it
\r
496 boolean resolved = resolveAugmentWithContext(modules, augment, context);
\r
497 // while not resolved
\r
499 while (!(resolved) && j < allAugments.size()) {
\r
500 // try to resolve next augment
\r
501 resolveAugmentWithContext(modules, allAugments.get(j), context);
\r
502 // then try to resolve first again
\r
503 resolved = resolveAugmentWithContext(modules, augment, context);
\r
508 throw new YangParseException(augment.getModuleName(), augment.getLine(),
\r
509 "Error in augment parsing: failed to find augment target");
\r
515 * Search for augment target and perform augmentation.
\r
518 * all loaded modules
\r
520 * augment to resolve
\r
522 * SchemaContext containing already resolved modules
\r
523 * @return true if target node found, false otherwise
\r
525 private boolean resolveAugmentWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
526 final AugmentationSchemaBuilder augment, final SchemaContext context) {
\r
527 if (augment.isResolved()) {
\r
530 int line = augment.getLine();
\r
531 ModuleBuilder module = getParentModule(augment);
\r
532 List<QName> path = augment.getTargetPath().getPath();
\r
533 final QName firstNameInPath = path.get(0);
\r
534 String prefix = firstNameInPath.getPrefix();
\r
535 if (prefix == null) {
\r
536 prefix = module.getPrefix();
\r
538 Builder augmentParent = augment.getParent();
\r
539 Builder currentParent = null;
\r
541 if (augmentParent instanceof ModuleBuilder) {
\r
542 // if augment is defined under module, first parent is target module
\r
543 currentParent = findDependentModuleBuilder(modules, module, prefix, line);
\r
544 } else if (augmentParent instanceof UsesNodeBuilder) {
\r
545 currentParent = augmentParent.getParent();
\r
547 // augment can be defined only under module or uses
\r
548 throw new YangParseException(augment.getModuleName(), augment.getLine(),
\r
549 "Error in augment parsing: Unresolved parent of augment: " + augmentParent);
\r
552 if (currentParent == null) {
\r
553 return processAugmentationOnContext(augment, path, module, prefix, context);
\r
555 return processAugmentation(augment, currentParent, path);
\r
560 * Go through identity statements defined in current module and resolve
\r
561 * their 'base' statement if present.
\r
566 * module being resolved
\r
568 private void resolveIdentities(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
\r
569 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
\r
570 for (IdentitySchemaNodeBuilder identity : identities) {
\r
571 final String baseIdentityName = identity.getBaseIdentityName();
\r
572 if (baseIdentityName != null) {
\r
573 String baseIdentityPrefix = null;
\r
574 String baseIdentityLocalName = null;
\r
575 if (baseIdentityName.contains(":")) {
\r
576 final String[] splitted = baseIdentityName.split(":");
\r
577 baseIdentityPrefix = splitted[0];
\r
578 baseIdentityLocalName = splitted[1];
\r
580 baseIdentityPrefix = module.getPrefix();
\r
581 baseIdentityLocalName = baseIdentityName;
\r
583 final ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, baseIdentityPrefix,
\r
584 identity.getLine());
\r
586 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule.getIdentities();
\r
587 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
\r
588 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
\r
589 identity.setBaseIdentity(idBuilder);
\r
597 * Go through identity statements defined in current module and resolve
\r
598 * their 'base' statement. Method tries to find base identity in given
\r
599 * modules. If base identity is not found, method will search it in context.
\r
602 * all loaded modules
\r
606 * SchemaContext containing already resolved modules
\r
608 private void resolveIdentitiesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
609 final ModuleBuilder module, final SchemaContext context) {
\r
610 final Set<IdentitySchemaNodeBuilder> identities = module.getIdentities();
\r
611 for (IdentitySchemaNodeBuilder identity : identities) {
\r
612 final String baseIdentityName = identity.getBaseIdentityName();
\r
613 if (baseIdentityName != null) {
\r
614 String baseIdentityPrefix = null;
\r
615 String baseIdentityLocalName = null;
\r
616 if (baseIdentityName.contains(":")) {
\r
617 final String[] splitted = baseIdentityName.split(":");
\r
618 baseIdentityPrefix = splitted[0];
\r
619 baseIdentityLocalName = splitted[1];
\r
621 baseIdentityPrefix = module.getPrefix();
\r
622 baseIdentityLocalName = baseIdentityName;
\r
624 final ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
\r
625 baseIdentityPrefix, identity.getLine());
\r
627 if (dependentModuleBuilder == null) {
\r
628 final Module dependentModule = findModuleFromContext(context, module, baseIdentityPrefix,
\r
629 identity.getLine());
\r
630 final Set<IdentitySchemaNode> dependentModuleIdentities = dependentModule.getIdentities();
\r
631 for (IdentitySchemaNode idNode : dependentModuleIdentities) {
\r
632 if (idNode.getQName().getLocalName().equals(baseIdentityLocalName)) {
\r
633 identity.setBaseIdentity(idNode);
\r
637 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModuleBuilder
\r
639 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
\r
640 if (idBuilder.getQName().getLocalName().equals(baseIdentityLocalName)) {
\r
641 identity.setBaseIdentity(idBuilder);
\r
650 * Find and add reference of uses target grouping.
\r
653 * all loaded modules
\r
655 * SchemaContext containing already resolved modules or null if
\r
656 * context is not available
\r
658 private void findUsesTargets(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final SchemaContext context) {
\r
659 final List<UsesNodeBuilder> allUses = new ArrayList<>();
\r
660 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
661 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
662 allUses.addAll(inner.getValue().getAllUsesNodes());
\r
665 for (UsesNodeBuilder usesNode : allUses) {
\r
666 ModuleBuilder module = ParserUtils.getParentModule(usesNode);
\r
667 final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
\r
669 if (targetGroupingBuilder == null) {
\r
670 if (context == null) {
\r
671 throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
\r
672 + usesNode.getGroupingPathAsString() + "' not found.");
\r
674 GroupingDefinition targetGroupingDefinition = GroupingUtils.getTargetGroupingFromContext(usesNode,
\r
676 usesNode.setGroupingDefinition(targetGroupingDefinition);
\r
679 usesNode.setGrouping(targetGroupingBuilder);
\r
685 * Copy data from uses target, update uses parent and perform refinement.
\r
686 * Augmentations have to be resolved already.
\r
689 * all loaded modules
\r
691 private void resolveUses(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
692 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
693 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
694 ModuleBuilder module = inner.getValue();
\r
695 List<UsesNodeBuilder> usesNodes = null;
\r
696 boolean dataCollected = module.isAllUsesDataCollected();
\r
698 while (!dataCollected) {
\r
699 usesNodes = new ArrayList<>(module.getAllUsesNodes());
\r
700 for (UsesNodeBuilder usesNode : usesNodes) {
\r
701 if (!usesNode.isDataCollected()) {
\r
702 GroupingUtils.collectUsesData(usesNode);
\r
705 dataCollected = module.isAllUsesDataCollected();
\r
710 // new loop is must because in collecting data process new uses could
\r
712 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
\r
713 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
714 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
715 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
\r
719 for (UsesNodeBuilder usesNode : allModulesUses) {
\r
720 GroupingUtils.updateUsesParent(usesNode);
\r
721 GroupingUtils.performRefine(usesNode);
\r
723 for (UsesNodeBuilder usesNode : allModulesUses) {
\r
724 GroupingUtils.fixUsesNodesPath(usesNode);
\r
727 for (UsesNodeBuilder usesNode : allModulesUses) {
\r
728 if (usesNode.isCopy()) {
\r
729 usesNode.getParent().getUsesNodes().remove(usesNode);
\r
735 * Copy data from uses target, update uses parent and perform refinement.
\r
736 * Augmentations have to be resolved already.
\r
739 * all loaded modules
\r
741 * SchemaContext containing already resolved modules
\r
743 private void resolveUsesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
744 final SchemaContext context) {
\r
745 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
746 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
747 ModuleBuilder module = inner.getValue();
\r
748 List<UsesNodeBuilder> usesNodes = null;
\r
749 boolean dataCollected = module.isAllUsesDataCollected();
\r
751 while (!dataCollected) {
\r
752 usesNodes = new ArrayList<>(module.getAllUsesNodes());
\r
753 for (UsesNodeBuilder usesNode : usesNodes) {
\r
754 if (!usesNode.isDataCollected()) {
\r
755 if (usesNode.getGroupingBuilder() == null) {
\r
756 GroupingUtils.collectUsesDataFromContext(usesNode);
\r
758 GroupingUtils.collectUsesData(usesNode);
\r
762 dataCollected = module.isAllUsesDataCollected();
\r
767 // new loop is must because in collecting data process new uses could
\r
769 final List<UsesNodeBuilder> allModulesUses = new ArrayList<>();
\r
770 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
771 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
772 allModulesUses.addAll(inner.getValue().getAllUsesNodes());
\r
776 for (UsesNodeBuilder usesNode : allModulesUses) {
\r
777 GroupingUtils.updateUsesParent(usesNode);
\r
778 GroupingUtils.performRefine(usesNode);
\r
780 for (UsesNodeBuilder usesNode : allModulesUses) {
\r
781 GroupingUtils.fixUsesNodesPath(usesNode);
\r
785 private void resolveUnknownNodes(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
\r
786 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
\r
787 QName nodeType = usnb.getNodeType();
\r
789 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, nodeType.getPrefix(),
\r
791 for (ExtensionBuilder extension : dependentModule.getExtensions()) {
\r
792 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
\r
793 usnb.setNodeType(extension.getQName());
\r
794 usnb.setExtensionBuilder(extension);
\r
798 } catch (YangParseException e) {
\r
799 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
\r
800 + ": no such extension definition found.");
\r
805 private void resolveUnknownNodesWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
806 final ModuleBuilder module, final SchemaContext context) {
\r
807 for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
\r
808 QName nodeType = usnb.getNodeType();
\r
810 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module,
\r
811 nodeType.getPrefix(), usnb.getLine());
\r
813 if (dependentModuleBuilder == null) {
\r
814 Module dependentModule = findModuleFromContext(context, module, nodeType.getPrefix(),
\r
816 for (ExtensionDefinition e : dependentModule.getExtensionSchemaNodes()) {
\r
817 if (e.getQName().getLocalName().equals(nodeType.getLocalName())) {
\r
818 usnb.setNodeType(new QName(e.getQName().getNamespace(), e.getQName().getRevision(),
\r
819 nodeType.getPrefix(), e.getQName().getLocalName()));
\r
820 usnb.setExtensionDefinition(e);
\r
825 for (ExtensionBuilder extension : dependentModuleBuilder.getExtensions()) {
\r
826 if (extension.getQName().getLocalName().equals(nodeType.getLocalName())) {
\r
827 usnb.setExtensionBuilder(extension);
\r
833 } catch (YangParseException e) {
\r
834 throw new YangParseException(module.getName(), usnb.getLine(), "Failed to resolve node " + usnb
\r
835 + ": no such extension definition found.");
\r
842 * Traverse through modules and resolve their deviation statements.
\r
845 * all loaded modules
\r
847 private void resolveDeviations(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
\r
848 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
849 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
850 ModuleBuilder b = inner.getValue();
\r
851 resolveDeviation(modules, b);
\r
857 * Traverse through module and resolve its deviation statements.
\r
860 * all loaded modules
\r
862 * module in which resolve deviations
\r
864 private void resolveDeviation(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
\r
865 for (DeviationBuilder dev : module.getDeviations()) {
\r
866 int line = dev.getLine();
\r
867 SchemaPath targetPath = dev.getTargetPath();
\r
868 List<QName> path = targetPath.getPath();
\r
869 QName q0 = path.get(0);
\r
870 String prefix = q0.getPrefix();
\r
871 if (prefix == null) {
\r
872 prefix = module.getPrefix();
\r
875 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
\r
876 processDeviation(dev, dependentModuleBuilder, path, module);
\r
881 * Traverse through modules and resolve their deviation statements with
\r
885 * all loaded modules
\r
887 * already resolved context
\r
889 private void resolveDeviationsWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
890 final SchemaContext context) {
\r
891 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
\r
892 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue().entrySet()) {
\r
893 ModuleBuilder b = inner.getValue();
\r
894 resolveDeviationWithContext(modules, b, context);
\r
900 * Traverse through module and resolve its deviation statements with given
\r
904 * all loaded modules
\r
906 * module in which resolve deviations
\r
908 * already resolved context
\r
910 private void resolveDeviationWithContext(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
\r
911 final ModuleBuilder module, final SchemaContext context) {
\r
912 for (DeviationBuilder dev : module.getDeviations()) {
\r
913 int line = dev.getLine();
\r
914 SchemaPath targetPath = dev.getTargetPath();
\r
915 List<QName> path = targetPath.getPath();
\r
916 QName q0 = path.get(0);
\r
917 String prefix = q0.getPrefix();
\r
918 if (prefix == null) {
\r
919 prefix = module.getPrefix();
\r
921 String name = null;
\r
923 ModuleBuilder dependentModuleBuilder = findDependentModuleBuilder(modules, module, prefix, line);
\r
924 if (dependentModuleBuilder == null) {
\r
925 Module dependentModule = findModuleFromContext(context, module, prefix, line);
\r
926 Object currentParent = dependentModule;
\r
928 for (int i = 0; i < path.size(); i++) {
\r
929 if (currentParent == null) {
\r
930 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
\r
932 QName q = path.get(i);
\r
933 name = q.getLocalName();
\r
934 if (currentParent instanceof DataNodeContainer) {
\r
935 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(name);
\r
939 if (currentParent == null) {
\r
940 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
\r
942 if (currentParent instanceof SchemaNode) {
\r
943 dev.setTargetPath(((SchemaNode) currentParent).getPath());
\r
947 processDeviation(dev, dependentModuleBuilder, path, module);
\r
953 * Correct deviation target path in deviation builder.
\r
957 * @param dependentModuleBuilder
\r
958 * module containing deviation target
\r
960 * current deviation target path
\r
964 private void processDeviation(final DeviationBuilder dev, final ModuleBuilder dependentModuleBuilder,
\r
965 final List<QName> path, final ModuleBuilder module) {
\r
966 final int line = dev.getLine();
\r
967 Builder currentParent = dependentModuleBuilder;
\r
969 for (int i = 0; i < path.size(); i++) {
\r
970 if (currentParent == null) {
\r
971 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
\r
973 QName q = path.get(i);
\r
974 String name = q.getLocalName();
\r
975 if (currentParent instanceof DataNodeContainerBuilder) {
\r
976 currentParent = ((DataNodeContainerBuilder) currentParent).getDataChildByName(name);
\r
980 if (currentParent == null || !(currentParent instanceof SchemaNodeBuilder)) {
\r
981 throw new YangParseException(module.getName(), line, "Failed to find deviation target.");
\r
983 dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
\r