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.controller.yang.parser.impl;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.HashMap;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.LinkedHashMap;
22 import java.util.List;
24 import java.util.Map.Entry;
25 import java.util.NoSuchElementException;
27 import java.util.TreeMap;
29 import org.antlr.v4.runtime.ANTLRInputStream;
30 import org.antlr.v4.runtime.CommonTokenStream;
31 import org.antlr.v4.runtime.tree.ParseTree;
32 import org.antlr.v4.runtime.tree.ParseTreeWalker;
33 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
35 import org.opendaylight.controller.yang.common.QName;
36 import org.opendaylight.controller.yang.model.api.Module;
37 import org.opendaylight.controller.yang.model.api.ModuleImport;
38 import org.opendaylight.controller.yang.model.api.SchemaContext;
39 import org.opendaylight.controller.yang.model.api.SchemaPath;
40 import org.opendaylight.controller.yang.model.api.TypeDefinition;
41 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
42 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
45 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
46 import org.opendaylight.controller.yang.model.util.ExtendedType;
47 import org.opendaylight.controller.yang.model.util.IdentityrefType;
48 import org.opendaylight.controller.yang.model.util.UnknownType;
49 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
50 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
51 import org.opendaylight.controller.yang.parser.builder.api.Builder;
52 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
53 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
54 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
55 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
56 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
57 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
58 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
59 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
60 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
61 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
63 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
64 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
65 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
66 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
70 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
72 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
73 import org.opendaylight.controller.yang.parser.util.ParserUtils;
74 import org.opendaylight.controller.yang.parser.util.RefineHolder;
75 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
76 import org.opendaylight.controller.yang.parser.util.YangParseException;
77 import org.opendaylight.controller.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 {
87 private static final Logger logger = LoggerFactory
88 .getLogger(YangParserImpl.class);
91 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
92 if (yangFiles != null) {
93 final Map<InputStream, File> inputStreams = Maps.newHashMap();
95 for (final File yangFile : yangFiles) {
97 inputStreams.put(new FileInputStream(yangFile), yangFile);
98 } catch (FileNotFoundException e) {
99 logger.warn("Exception while reading yang file: "
100 + yangFile.getName(), e);
104 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps
107 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
108 Lists.newArrayList(inputStreams.keySet()),
110 // return new LinkedHashSet<Module>(build(modules).values());
112 Map<File, Module> retVal = Maps.newLinkedHashMap();
113 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
115 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
117 retVal.put(inputStreams.get(builderToStreamMap
118 .get(builderToModule.getKey())), builderToModule
124 return Collections.emptyMap();
128 public Set<Module> parseYangModels(final List<File> yangFiles) {
129 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
133 public Set<Module> parseYangModelsFromStreams(
134 final List<InputStream> yangModelStreams) {
135 return Sets.newHashSet(parseYangModelsFromStreamsMapped(
136 yangModelStreams).values());
140 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(
141 final List<InputStream> yangModelStreams) {
142 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
144 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
145 yangModelStreams, builderToStreamMap);
146 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
147 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
149 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
151 retVal.put(builderToStreamMap.get(builderToModule.getKey()),
152 builderToModule.getValue());
158 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
159 return new SchemaContextImpl(modules);
162 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
163 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
165 final ParseTreeWalker walker = new ParseTreeWalker();
166 final List<ParseTree> trees = parseStreams(inputStreams);
167 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
170 new YangModelBasicValidator(walker).validate(trees);
172 YangParserListenerImpl yangModelParser = null;
173 for (int i = 0; i < trees.size(); i++) {
174 yangModelParser = new YangParserListenerImpl();
175 walker.walk(yangModelParser, trees.get(i));
176 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
178 // We expect the order of trees and streams has to be the same
179 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
180 builders[i] = moduleBuilder;
185 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
186 final List<InputStream> yangFileStreams,
187 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
189 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams,
192 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
193 // of items stored in map.
194 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
196 // module dependency graph sorted
197 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
199 for (ModuleBuilder builder : sorted) {
200 final String builderName = builder.getName();
201 Date builderRevision = builder.getRevision();
202 if (builderRevision == null) {
203 builderRevision = new Date(0L);
205 TreeMap<Date, ModuleBuilder> builderByRevision = modules
207 if (builderByRevision == null) {
208 builderByRevision = new TreeMap<Date, ModuleBuilder>();
210 builderByRevision.put(builderRevision, builder);
211 modules.put(builderName, builderByRevision);
216 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
217 final List<ParseTree> trees = new ArrayList<ParseTree>();
218 for (InputStream yangStream : yangStreams) {
219 trees.add(parseStream(yangStream));
224 private ParseTree parseStream(final InputStream yangStream) {
225 ParseTree result = null;
227 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
228 final YangLexer lexer = new YangLexer(input);
229 final CommonTokenStream tokens = new CommonTokenStream(lexer);
230 final YangParser parser = new YangParser(tokens);
232 result = parser.yang();
233 } catch (IOException e) {
234 logger.warn("Exception while reading yang file: " + yangStream, e);
239 private Map<ModuleBuilder, Module> build(
240 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
241 // fix unresolved nodes
242 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
244 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
246 final ModuleBuilder moduleBuilder = childEntry.getValue();
247 fixUnresolvedNodes(modules, moduleBuilder);
250 resolveAugments(modules);
253 // LinkedHashMap MUST be used otherwise the values will not maintain
255 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
256 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
257 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
259 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
260 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
262 final ModuleBuilder moduleBuilder = childEntry.getValue();
263 final Module module = moduleBuilder.build();
264 modulesByRevision.put(childEntry.getKey(), module);
265 result.put(moduleBuilder, module);
271 private void fixUnresolvedNodes(
272 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
273 final ModuleBuilder builder) {
274 resolveDirtyNodes(modules, builder);
275 resolveIdentities(modules, builder);
276 resolveUsesRefines(modules, builder);
277 resolveUnknownNodes(modules, builder);
281 * Search for dirty nodes (node which contains UnknownType) and resolve
285 * all available modules
289 private void resolveDirtyNodes(
290 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
291 final ModuleBuilder module) {
292 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
294 if (!dirtyNodes.isEmpty()) {
295 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
297 final TypeAwareBuilder nodeToResolve = entry.getValue();
299 if (nodeToResolve instanceof UnionTypeBuilder) {
300 // special handling for union types
301 resolveTypeUnion((UnionTypeBuilder) nodeToResolve, modules,
303 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
304 // special handling for identityref types
305 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
307 nodeToResolve.setType(new IdentityrefType(findFullQName(
308 modules, module, idref), idref.getPath()));
310 resolveType(nodeToResolve, modules, module);
316 private void resolveType(final TypeAwareBuilder nodeToResolve,
317 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
318 final ModuleBuilder builder) {
319 TypeDefinitionBuilder resolvedType = null;
320 final int line = nodeToResolve.getLine();
321 final TypeDefinition<?> typedefType = nodeToResolve.getType();
322 final QName unknownTypeQName = typedefType.getBaseType().getQName();
323 final ModuleBuilder dependentModule = findDependentModule(modules,
324 builder, unknownTypeQName.getPrefix(), line);
326 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(
327 nodeToResolve.getPath(), dependentModule,
328 unknownTypeQName.getLocalName(), builder.getName(), line);
330 if (typedefType instanceof ExtendedType) {
331 final ExtendedType extType = (ExtendedType) typedefType;
332 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(
333 nodeToResolve, targetTypeBuilder, extType, modules, builder);
334 resolvedType = newType;
336 resolvedType = targetTypeBuilder;
338 nodeToResolve.setTypedef(resolvedType);
341 private void resolveTypeUnion(final UnionTypeBuilder union,
342 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
343 final ModuleBuilder builder) {
345 final List<TypeDefinition<?>> unionTypes = union.getTypes();
346 final List<TypeDefinition<?>> toRemove = new ArrayList<TypeDefinition<?>>();
347 for (TypeDefinition<?> unionType : unionTypes) {
348 if (unionType instanceof UnknownType) {
349 final UnknownType ut = (UnknownType) unionType;
350 final ModuleBuilder dependentModule = findDependentModule(
351 modules, builder, ut.getQName().getPrefix(),
353 final TypeDefinitionBuilder resolvedType = findTypeDefinitionBuilder(
354 union.getPath(), dependentModule, ut.getQName()
355 .getLocalName(), builder.getName(),
357 union.setTypedef(resolvedType);
359 } else if (unionType instanceof ExtendedType) {
360 final ExtendedType extType = (ExtendedType) unionType;
361 TypeDefinition<?> extTypeBase = extType.getBaseType();
362 if (extTypeBase instanceof UnknownType) {
363 final UnknownType ut = (UnknownType) extTypeBase;
364 final ModuleBuilder dependentModule = findDependentModule(
365 modules, builder, ut.getQName().getPrefix(),
367 final TypeDefinitionBuilder targetTypeBuilder = findTypeDefinitionBuilder(
368 union.getPath(), dependentModule, ut.getQName()
369 .getLocalName(), builder.getName(),
372 final TypeDefinitionBuilder newType = extendedTypeWithNewBaseType(
373 targetTypeBuilder, targetTypeBuilder, extType,
376 union.setTypedef(newType);
377 toRemove.add(extType);
381 unionTypes.removeAll(toRemove);
384 private TypeDefinitionBuilder extendedTypeWithNewBaseType(
385 final TypeAwareBuilder nodeToResolve,
386 final TypeDefinitionBuilder newBaseType,
387 final ExtendedType oldExtendedType,
388 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
389 final ModuleBuilder builder) {
390 final TypeConstraints constraints = findConstraints(nodeToResolve,
391 new TypeConstraints(), modules, builder);
392 final TypeDefinitionBuilderImpl newType = new TypeDefinitionBuilderImpl(
393 oldExtendedType.getQName(), nodeToResolve.getLine());
394 newType.setTypedef(newBaseType);
395 newType.setPath(oldExtendedType.getPath());
396 newType.setDescription(oldExtendedType.getDescription());
397 newType.setReference(oldExtendedType.getReference());
398 newType.setStatus(oldExtendedType.getStatus());
399 newType.setLengths(constraints.getLength());
400 newType.setPatterns(constraints.getPatterns());
401 newType.setRanges(constraints.getRange());
402 newType.setFractionDigits(constraints.getFractionDigits());
403 newType.setUnits(oldExtendedType.getUnits());
404 newType.setDefaultValue(oldExtendedType.getDefaultValue());
405 newType.setUnknownNodes(oldExtendedType.getUnknownSchemaNodes());
409 private TypeConstraints findConstraints(
410 final TypeAwareBuilder nodeToResolve,
411 final TypeConstraints constraints,
412 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
413 final ModuleBuilder builder) {
415 // union type cannot be restricted
416 if (nodeToResolve instanceof UnionTypeBuilder) {
420 if (nodeToResolve instanceof TypeDefinitionBuilder) {
421 TypeDefinitionBuilder typedefToResolve = (TypeDefinitionBuilder) nodeToResolve;
422 constraints.addFractionDigits(typedefToResolve.getFractionDigits());
423 constraints.addLengths(typedefToResolve.getLengths());
424 constraints.addPatterns(typedefToResolve.getPatterns());
425 constraints.addRanges(typedefToResolve.getRanges());
428 TypeDefinition<?> type = nodeToResolve.getType();
430 return findConstraints(nodeToResolve.getTypedef(), constraints,
433 if (type instanceof UnknownType) {
434 ModuleBuilder dependentModule = findDependentModule(modules,
435 builder, type.getQName().getPrefix(),
436 nodeToResolve.getLine());
437 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(
438 nodeToResolve.getPath(), dependentModule, type
439 .getQName().getLocalName(), builder.getName(),
440 nodeToResolve.getLine());
441 return findConstraints(tdb, constraints, modules,
443 } else if (type instanceof ExtendedType) {
444 ExtendedType extType = (ExtendedType) type;
445 constraints.addFractionDigits(extType.getFractionDigits());
446 constraints.addLengths(extType.getLengths());
447 constraints.addPatterns(extType.getPatterns());
448 constraints.addRanges(extType.getRanges());
450 TypeDefinition<?> base = extType.getBaseType();
451 if (base instanceof UnknownType) {
452 ModuleBuilder dependentModule = findDependentModule(
453 modules, builder, base.getQName().getPrefix(),
454 nodeToResolve.getLine());
455 TypeDefinitionBuilder tdb = findTypeDefinitionBuilder(
456 nodeToResolve.getPath(), dependentModule, base
457 .getQName().getLocalName(),
458 builder.getName(), nodeToResolve.getLine());
459 return findConstraints(tdb, constraints, modules,
462 // it has to be base yang type
463 mergeConstraints(type, constraints);
467 // it is base yang type
468 mergeConstraints(type, constraints);
475 * Search for type definition builder by name.
477 * @param dirtyNodeSchemaPath
478 * schema path of node which contains unresolved type
479 * @param dependentModule
480 * module which should contains referenced type
482 * name of type definition
483 * @param currentModuleName
484 * name of current module
486 * current line in yang model
489 private TypeDefinitionBuilder findTypeDefinitionBuilder(
490 SchemaPath dirtyNodeSchemaPath,
491 final ModuleBuilder dependentModule, final String typeName,
492 final String currentModuleName, final int line) {
493 final List<QName> path = dirtyNodeSchemaPath.getPath();
494 TypeDefinitionBuilder result = null;
496 Set<TypeDefinitionBuilder> typedefs = dependentModule
497 .getModuleTypedefs();
498 result = findTdb(typedefs, typeName);
500 if (result == null) {
501 Builder currentNode = null;
502 final List<String> currentPath = new ArrayList<String>();
503 currentPath.add(dependentModule.getName());
505 for (int i = 0; i < path.size(); i++) {
506 QName qname = path.get(i);
507 currentPath.add(qname.getLocalName());
508 currentNode = dependentModule.getModuleNode(currentPath);
510 if (currentNode instanceof RpcDefinitionBuilder) {
511 typedefs = ((RpcDefinitionBuilder) currentNode)
512 .getTypeDefinitions();
513 } else if (currentNode instanceof DataNodeContainerBuilder) {
514 typedefs = ((DataNodeContainerBuilder) currentNode)
515 .getTypeDefinitions();
517 typedefs = Collections.emptySet();
520 result = findTdb(typedefs, typeName);
521 if (result != null) {
527 if (result != null) {
530 throw new YangParseException(currentModuleName, line,
531 "Referenced type '" + typeName + "' not found.");
534 private TypeDefinitionBuilder findTdb(Set<TypeDefinitionBuilder> types,
536 for (TypeDefinitionBuilder td : types) {
537 if (td.getQName().getLocalName().equals(name)) {
545 * Pull restriction from referenced type and add them to given constraints
547 * @param referencedType
550 private void mergeConstraints(final TypeDefinition<?> referencedType,
551 final TypeConstraints constraints) {
553 if (referencedType instanceof DecimalTypeDefinition) {
554 constraints.addRanges(((DecimalTypeDefinition) referencedType)
555 .getRangeStatements());
557 .addFractionDigits(((DecimalTypeDefinition) referencedType)
558 .getFractionDigits());
559 } else if (referencedType instanceof IntegerTypeDefinition) {
560 constraints.addRanges(((IntegerTypeDefinition) referencedType)
561 .getRangeStatements());
562 } else if (referencedType instanceof StringTypeDefinition) {
563 constraints.addPatterns(((StringTypeDefinition) referencedType)
565 constraints.addLengths(((StringTypeDefinition) referencedType)
566 .getLengthStatements());
567 } else if (referencedType instanceof BinaryTypeDefinition) {
568 constraints.addLengths(((BinaryTypeDefinition) referencedType)
569 .getLengthConstraints());
574 * Go through all augment definitions and resolve them. This method also
575 * finds augment target node and add child nodes to it.
578 * all available modules
580 private void resolveAugments(
581 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
582 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
583 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
584 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
586 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
588 allModulesList.add(inner.getValue());
589 allModulesSet.add(inner.getValue());
593 for (int i = 0; i < allModulesList.size(); i++) {
594 final ModuleBuilder module = allModulesList.get(i);
595 // try to resolve augments in module
596 resolveAugment(modules, module);
597 // while all augments are not resolved
598 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
600 while (!(module.getAugmentsResolved() == module.getAugments()
602 ModuleBuilder nextModule = null;
603 // try resolve other module augments
605 nextModule = allModulesIterator.next();
606 resolveAugment(modules, nextModule);
607 } catch (NoSuchElementException e) {
608 throw new YangParseException(
609 "Failed to resolve augments in module '"
610 + module.getName() + "'.", e);
612 // then try to resolve first module again
613 resolveAugment(modules, module);
621 * all available modules
625 private void resolveAugment(
626 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
627 final ModuleBuilder module) {
628 if (module.getAugmentsResolved() < module.getAugments().size()) {
629 for (AugmentationSchemaBuilder augmentBuilder : module
632 if (!augmentBuilder.isResolved()) {
633 final SchemaPath augmentTargetSchemaPath = augmentBuilder
635 final List<QName> path = augmentTargetSchemaPath.getPath();
637 final QName qname = path.get(0);
638 String prefix = qname.getPrefix();
639 if (prefix == null) {
640 prefix = module.getPrefix();
643 DataSchemaNodeBuilder currentParent = null;
644 final ModuleBuilder dependentModule = findDependentModule(
645 modules, module, prefix, augmentBuilder.getLine());
646 for (DataSchemaNodeBuilder child : dependentModule
648 final QName childQName = child.getQName();
649 if (childQName.getLocalName().equals(
650 qname.getLocalName())) {
651 currentParent = child;
656 if (currentParent == null) {
660 for (int i = 1; i < path.size(); i++) {
661 final QName currentQName = path.get(i);
662 DataSchemaNodeBuilder newParent = null;
663 for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent)
665 final QName childQName = child.getQName();
666 if (childQName.getLocalName().equals(
667 currentQName.getLocalName())) {
672 if (newParent == null) {
673 break; // node not found, quit search
675 currentParent = newParent;
679 final QName currentQName = currentParent.getQName();
680 final QName lastAugmentPathElement = path
681 .get(path.size() - 1);
682 if (currentQName.getLocalName().equals(
683 lastAugmentPathElement.getLocalName())) {
685 if (currentParent instanceof ChoiceBuilder) {
686 ParserUtils.fillAugmentTarget(augmentBuilder,
687 (ChoiceBuilder) currentParent);
689 ParserUtils.fillAugmentTarget(augmentBuilder,
690 (DataNodeContainerBuilder) currentParent);
692 ((AugmentationTargetBuilder) currentParent)
693 .addAugmentation(augmentBuilder);
694 SchemaPath oldPath = currentParent.getPath();
695 augmentBuilder.setTargetPath(new SchemaPath(oldPath
696 .getPath(), oldPath.isAbsolute()));
697 augmentBuilder.setResolved(true);
698 module.augmentResolved();
707 * Go through identity statements defined in current module and resolve
708 * their 'base' statement if present.
713 * module being resolved
715 private void resolveIdentities(
716 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
717 final ModuleBuilder module) {
718 final Set<IdentitySchemaNodeBuilder> identities = module
720 for (IdentitySchemaNodeBuilder identity : identities) {
721 final String baseIdentityName = identity.getBaseIdentityName();
722 if (baseIdentityName != null) {
723 String baseIdentityPrefix = null;
724 String baseIdentityLocalName = null;
725 if (baseIdentityName.contains(":")) {
726 final String[] splitted = baseIdentityName.split(":");
727 baseIdentityPrefix = splitted[0];
728 baseIdentityLocalName = splitted[1];
730 baseIdentityPrefix = module.getPrefix();
731 baseIdentityLocalName = baseIdentityName;
733 final ModuleBuilder dependentModule = findDependentModule(
734 modules, module, baseIdentityPrefix, identity.getLine());
736 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
738 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
739 if (idBuilder.getQName().getLocalName()
740 .equals(baseIdentityLocalName)) {
741 identity.setBaseIdentity(idBuilder);
749 * Go through uses statements defined in current module and resolve their
755 * module being resolved
757 private void resolveUsesRefines(
758 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
759 final ModuleBuilder module) {
760 final Map<List<String>, UsesNodeBuilder> moduleUses = module
762 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
764 final UsesNodeBuilder usesNode = entry.getValue();
765 final int line = usesNode.getLine();
767 GroupingBuilder targetGrouping = getTargetGrouping(usesNode, modules, module);
768 usesNode.setGroupingPath(targetGrouping.getPath());
770 for (RefineHolder refine : usesNode.getRefines()) {
771 SchemaNodeBuilder refineTarget = getRefineNodeBuilderCopy(
772 targetGrouping, refine, modules, module);
773 ParserUtils.checkRefine(refineTarget, refine);
774 ParserUtils.refineDefault(refineTarget, refine, line);
775 if (refineTarget instanceof LeafSchemaNodeBuilder) {
776 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
777 ParserUtils.refineLeaf(leaf, refine, line);
778 usesNode.addRefineNode(leaf);
779 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
780 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
781 ParserUtils.refineContainer(container, refine, line);
782 usesNode.addRefineNode(container);
783 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
784 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
785 ParserUtils.refineList(list, refine, line);
786 usesNode.addRefineNode(list);
787 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
788 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) refineTarget;
789 ParserUtils.refineLeafList(leafList, refine, line);
790 usesNode.addRefineNode(leafList);
791 } else if (refineTarget instanceof ChoiceBuilder) {
792 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
793 ParserUtils.refineChoice(choice, refine, line);
794 usesNode.addRefineNode(choice);
795 } else if (refineTarget instanceof AnyXmlBuilder) {
796 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
797 ParserUtils.refineAnyxml(anyXml, refine, line);
798 usesNode.addRefineNode(anyXml);
799 } else if (refineTarget instanceof GroupingBuilder) {
800 usesNode.addRefineNode(refineTarget);
801 } else if (refineTarget instanceof TypeDefinitionBuilder) {
802 usesNode.addRefineNode(refineTarget);
808 private GroupingBuilder getTargetGrouping(
809 final UsesNodeBuilder usesBuilder,
810 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
811 final ModuleBuilder module) {
812 final int line = usesBuilder.getLine();
813 String groupingString = usesBuilder.getGroupingName();
814 String groupingPrefix;
817 if(groupingString.contains(":")) {
818 String[] splitted = groupingString.split(":");
819 if(splitted.length != 2 || groupingString.contains("/")) {
820 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
822 groupingPrefix = splitted[0];
823 groupingName = splitted[1];
825 groupingPrefix = module.getPrefix();
826 groupingName = groupingString;
829 ModuleBuilder dependentModule = null;
830 if(groupingPrefix.equals(module.getPrefix())) {
831 dependentModule = module;
833 dependentModule = findDependentModule(modules, module, groupingPrefix, line);
837 List<QName> path = usesBuilder.getPath().getPath();
838 GroupingBuilder result = null;
839 Set<GroupingBuilder> groupings = dependentModule.getModuleGroupings();
840 result = findGrouping(groupings, groupingName);
842 if (result == null) {
843 Builder currentNode = null;
844 final List<String> currentPath = new ArrayList<String>();
845 currentPath.add(dependentModule.getName());
847 for (int i = 0; i < path.size(); i++) {
848 QName qname = path.get(i);
849 currentPath.add(qname.getLocalName());
850 currentNode = dependentModule.getModuleNode(currentPath);
852 if (currentNode instanceof RpcDefinitionBuilder) {
853 groupings = ((RpcDefinitionBuilder) currentNode).getGroupings();
854 } else if (currentNode instanceof DataNodeContainerBuilder) {
855 groupings = ((DataNodeContainerBuilder) currentNode).getGroupings();
857 groupings = Collections.emptySet();
860 result = findGrouping(groupings, groupingName);
861 if (result != null) {
867 if (result != null) {
870 throw new YangParseException(module.getName(), line,
871 "Referenced grouping '" + groupingName + "' not found.");
874 private GroupingBuilder findGrouping(Set<GroupingBuilder> groupings,
876 for (GroupingBuilder grouping : groupings) {
877 if (grouping.getQName().getLocalName().equals(name)) {
885 * Find original builder of node to refine and return copy of this builder.
887 * We must create and use a copy of builder to preserve original builder
888 * state, because this object will be refined (modified) and later added to
889 * {@link UsesNodeBuilder}.
892 * @param groupingPath
893 * path to grouping which contains node to refine
895 * refine object containing informations about refine
900 * @return copy of node to be refined if it is present in grouping, null
903 private SchemaNodeBuilder getRefineNodeBuilderCopy(
904 final GroupingBuilder targetGrouping, final RefineHolder refine,
905 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
906 final ModuleBuilder module) {
907 Builder result = null;
908 final Builder lookedUpBuilder = findRefineTargetBuilder(targetGrouping,
909 refine, modules, module);
910 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
912 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
913 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
915 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
916 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
918 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
919 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
921 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
922 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
924 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
925 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
927 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
928 } else if (lookedUpBuilder instanceof GroupingBuilder) {
930 .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder);
931 } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
933 .copyTypedefBuilder((TypeDefinitionBuilderImpl) lookedUpBuilder);
935 throw new YangParseException(module.getName(), refine.getLine(),
936 "Target '" + refine.getName() + "' can not be refined");
938 return (SchemaNodeBuilder) result;
942 * Find builder of refine node.
944 * @param groupingPath
945 * path to grouping which contains node to refine
947 * object containing refine information
952 * @return Builder object of refine node if it is present in grouping, null
955 private Builder findRefineTargetBuilder(final GroupingBuilder builder,
956 final RefineHolder refine,
957 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
958 final ModuleBuilder module) {
959 final String refineNodeName = refine.getName();
960 Builder result = builder.getChildNode(refineNodeName);
961 if (result == null) {
962 Set<GroupingBuilder> grps = builder.getGroupings();
963 for (GroupingBuilder gr : grps) {
964 if (gr.getQName().getLocalName().equals(refineNodeName)) {
970 if (result == null) {
971 Set<TypeDefinitionBuilder> typedefs = builder.getTypeDefinitions();
972 for (TypeDefinitionBuilder typedef : typedefs) {
973 if (typedef.getQName().getLocalName().equals(refineNodeName)) {
982 private QName findFullQName(
983 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
984 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
986 String baseString = idref.getBaseString();
987 if (baseString.contains(":")) {
988 String[] splittedBase = baseString.split(":");
989 if (splittedBase.length > 2) {
990 throw new YangParseException(module.getName(), idref.getLine(),
991 "Failed to parse identityref base: " + baseString);
993 String prefix = splittedBase[0];
994 String name = splittedBase[1];
995 ModuleBuilder dependentModule = findDependentModule(modules,
996 module, prefix, idref.getLine());
997 result = new QName(dependentModule.getNamespace(),
998 dependentModule.getRevision(), prefix, name);
1000 result = new QName(module.getNamespace(), module.getRevision(),
1001 module.getPrefix(), baseString);
1006 private void resolveUnknownNodes(
1007 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1008 final ModuleBuilder module) {
1009 for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) {
1010 QName nodeType = usnb.getNodeType();
1011 if (nodeType.getNamespace() == null
1012 || nodeType.getRevision() == null) {
1014 ModuleBuilder dependentModule = findDependentModule(
1015 modules, module, nodeType.getPrefix(),
1017 QName newNodeType = new QName(
1018 dependentModule.getNamespace(),
1019 dependentModule.getRevision(),
1020 nodeType.getPrefix(), nodeType.getLocalName());
1021 usnb.setNodeType(newNodeType);
1022 } catch (YangParseException e) {
1023 logger.debug(module.getName(), usnb.getLine(),
1024 "Failed to find unknown node type: " + nodeType);
1031 * Find dependent module based on given prefix
1034 * all available modules
1038 * target module prefix
1040 * current line in yang model
1043 private ModuleBuilder findDependentModule(
1044 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1045 final ModuleBuilder module, final String prefix, final int line) {
1046 ModuleBuilder dependentModule = null;
1047 Date dependentModuleRevision = null;
1049 if (prefix.equals(module.getPrefix())) {
1050 dependentModule = module;
1052 final ModuleImport dependentModuleImport = ParserUtils
1053 .getModuleImport(module, prefix);
1054 if (dependentModuleImport == null) {
1055 throw new YangParseException(module.getName(), line,
1056 "No import found with prefix '" + prefix + "'.");
1058 final String dependentModuleName = dependentModuleImport
1060 dependentModuleRevision = dependentModuleImport.getRevision();
1062 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1063 .get(dependentModuleName);
1064 if (moduleBuildersByRevision == null) {
1065 throw new YangParseException(module.getName(), line,
1066 "Failed to find dependent module '"
1067 + dependentModuleName + "'.");
1069 if (dependentModuleRevision == null) {
1070 dependentModule = moduleBuildersByRevision.lastEntry()
1073 dependentModule = moduleBuildersByRevision
1074 .get(dependentModuleRevision);
1078 if (dependentModule == null) {
1079 throw new YangParseException(module.getName(), line,
1080 "Failed to find dependent module with prefix '" + prefix
1081 + "' and revision '" + dependentModuleRevision
1084 return dependentModule;