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.LengthConstraint;
45 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
46 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
47 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
48 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
49 import org.opendaylight.controller.yang.model.util.ExtendedType;
50 import org.opendaylight.controller.yang.model.util.IdentityrefType;
51 import org.opendaylight.controller.yang.model.util.UnknownType;
52 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
53 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
54 import org.opendaylight.controller.yang.parser.builder.api.Builder;
55 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
56 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
57 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
58 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
61 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
63 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
64 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
65 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
66 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.RpcDefinitionBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
73 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
74 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
75 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
76 import org.opendaylight.controller.yang.parser.util.ParserUtils;
77 import org.opendaylight.controller.yang.parser.util.RefineHolder;
78 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
79 import org.opendaylight.controller.yang.parser.util.YangParseException;
80 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 import com.google.common.collect.Lists;
85 import com.google.common.collect.Maps;
86 import com.google.common.collect.Sets;
88 public final class YangParserImpl implements YangModelParser {
90 private static final Logger logger = LoggerFactory
91 .getLogger(YangParserImpl.class);
94 public Map<File, Module> parseYangModelsMapped(List<File> yangFiles) {
95 if (yangFiles != null) {
96 final Map<InputStream, File> inputStreams = Maps.newHashMap();
98 for (final File yangFile : yangFiles) {
100 inputStreams.put(new FileInputStream(yangFile), yangFile);
101 } catch (FileNotFoundException e) {
102 logger.warn("Exception while reading yang file: "
103 + yangFile.getName(), e);
107 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps
110 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
111 Lists.newArrayList(inputStreams.keySet()),
113 // return new LinkedHashSet<Module>(build(modules).values());
115 Map<File, Module> retVal = Maps.newLinkedHashMap();
116 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
118 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
120 retVal.put(inputStreams.get(builderToStreamMap
121 .get(builderToModule.getKey())), builderToModule
127 return Collections.emptyMap();
131 public Set<Module> parseYangModels(final List<File> yangFiles) {
132 return Sets.newLinkedHashSet(parseYangModelsMapped(yangFiles).values());
136 public Set<Module> parseYangModelsFromStreams(
137 final List<InputStream> yangModelStreams) {
138 return Sets.newHashSet(parseYangModelsFromStreamsMapped(
139 yangModelStreams).values());
143 public Map<InputStream, Module> parseYangModelsFromStreamsMapped(
144 final List<InputStream> yangModelStreams) {
145 Map<ModuleBuilder, InputStream> builderToStreamMap = Maps.newHashMap();
147 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(
148 yangModelStreams, builderToStreamMap);
149 Map<InputStream, Module> retVal = Maps.newLinkedHashMap();
150 Map<ModuleBuilder, Module> builderToModuleMap = build(modules);
152 for (Entry<ModuleBuilder, Module> builderToModule : builderToModuleMap
154 retVal.put(builderToStreamMap.get(builderToModule.getKey()),
155 builderToModule.getValue());
161 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
162 return new SchemaContextImpl(modules);
165 private ModuleBuilder[] parseModuleBuilders(List<InputStream> inputStreams,
166 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
168 final ParseTreeWalker walker = new ParseTreeWalker();
169 final List<ParseTree> trees = parseStreams(inputStreams);
170 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
173 new YangModelBasicValidator(walker).validate(trees);
175 YangParserListenerImpl yangModelParser = null;
176 for (int i = 0; i < trees.size(); i++) {
177 yangModelParser = new YangParserListenerImpl();
178 walker.walk(yangModelParser, trees.get(i));
179 ModuleBuilder moduleBuilder = yangModelParser.getModuleBuilder();
181 // We expect the order of trees and streams has to be the same
182 streamToBuilderMap.put(moduleBuilder, inputStreams.get(i));
183 builders[i] = moduleBuilder;
188 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
189 final List<InputStream> yangFileStreams,
190 Map<ModuleBuilder, InputStream> streamToBuilderMap) {
192 final ModuleBuilder[] builders = parseModuleBuilders(yangFileStreams,
195 // Linked Hash Map MUST be used because Linked Hash Map preserves ORDER
196 // of items stored in map.
197 final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
199 // module dependency graph sorted
200 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
202 for (ModuleBuilder builder : sorted) {
203 final String builderName = builder.getName();
204 Date builderRevision = builder.getRevision();
205 if (builderRevision == null) {
206 builderRevision = new Date(0L);
208 TreeMap<Date, ModuleBuilder> builderByRevision = modules
210 if (builderByRevision == null) {
211 builderByRevision = new TreeMap<Date, ModuleBuilder>();
213 builderByRevision.put(builderRevision, builder);
214 modules.put(builderName, builderByRevision);
219 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
220 final List<ParseTree> trees = new ArrayList<ParseTree>();
221 for (InputStream yangStream : yangStreams) {
222 trees.add(parseStream(yangStream));
227 private ParseTree parseStream(final InputStream yangStream) {
228 ParseTree result = null;
230 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
231 final YangLexer lexer = new YangLexer(input);
232 final CommonTokenStream tokens = new CommonTokenStream(lexer);
233 final YangParser parser = new YangParser(tokens);
234 result = parser.yang();
235 } catch (IOException e) {
236 logger.warn("Exception while reading yang file: " + yangStream, e);
241 private Map<ModuleBuilder, Module> build(
242 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
243 // fix unresolved nodes
244 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
246 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
248 final ModuleBuilder moduleBuilder = childEntry.getValue();
249 fixUnresolvedNodes(modules, moduleBuilder);
252 resolveAugments(modules);
255 // LinkedHashMap MUST be used otherwise the values will not maintain
257 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html
258 final Map<ModuleBuilder, Module> result = new LinkedHashMap<ModuleBuilder, Module>();
259 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
261 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
262 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
264 final ModuleBuilder moduleBuilder = childEntry.getValue();
265 final Module module = moduleBuilder.build();
266 modulesByRevision.put(childEntry.getKey(), module);
267 result.put(moduleBuilder, module);
273 private void fixUnresolvedNodes(
274 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
275 final ModuleBuilder builder) {
276 resolveDirtyNodes(modules, builder);
277 resolveIdentities(modules, builder);
278 resolveUsesRefines(modules, builder);
279 resolveUnknownNodes(modules, builder);
283 * Search for dirty nodes (node which contains UnknownType) and resolve
287 * all available modules
291 private void resolveDirtyNodes(
292 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
293 final ModuleBuilder module) {
294 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
296 if (!dirtyNodes.isEmpty()) {
297 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
300 final TypeAwareBuilder nodeToResolve = entry.getValue();
301 // different handling for union types
302 if (nodeToResolve instanceof UnionTypeBuilder) {
303 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
304 final List<TypeDefinition<?>> unionTypes = union.getTypes();
305 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
306 for (TypeDefinition<?> td : unionTypes) {
307 if (td instanceof UnknownType) {
308 final UnknownType unknownType = (UnknownType) td;
309 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
310 nodeToResolve, unknownType, modules, module);
311 union.setTypedef(resolvedType);
312 toRemove.add(unknownType);
315 unionTypes.removeAll(toRemove);
316 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
317 // different handling for identityref types
318 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
320 nodeToResolve.setType(new IdentityrefType(findFullQName(
321 modules, module, idref), idref.getPath()));
323 final TypeDefinitionBuilder resolvedType = resolveType(
324 nodeToResolve, modules, module);
325 nodeToResolve.setTypedef(resolvedType);
331 private TypeDefinitionBuilder resolveType(
332 final TypeAwareBuilder nodeToResolve,
333 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
334 final ModuleBuilder builder) {
335 final TypeConstraints constraints = new TypeConstraints();
337 final TypeDefinitionBuilder targetTypeBuilder = getTypeDefinitionBuilderFromDirtyNode(
338 nodeToResolve, modules, builder);
339 final TypeConstraints tConstraints = findConstraints(nodeToResolve,
340 constraints, modules, builder);
341 targetTypeBuilder.setRanges(tConstraints.getRange());
342 targetTypeBuilder.setLengths(tConstraints.getLength());
343 targetTypeBuilder.setPatterns(tConstraints.getPatterns());
344 targetTypeBuilder.setFractionDigits(tConstraints.getFractionDigits());
346 return targetTypeBuilder;
349 private TypeDefinitionBuilder resolveTypeUnion(
350 final TypeAwareBuilder typeToResolve,
351 final UnknownType unknownType,
352 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
353 final ModuleBuilder builder) {
354 final TypeConstraints constraints = new TypeConstraints();
356 final TypeDefinitionBuilder targetTypeBuilder = getUnionBuilder(
357 typeToResolve, unknownType, modules, builder);
358 final TypeConstraints tConstraints = findConstraints(typeToResolve,
359 constraints, modules, builder);
360 targetTypeBuilder.setRanges(tConstraints.getRange());
361 targetTypeBuilder.setLengths(tConstraints.getLength());
362 targetTypeBuilder.setPatterns(tConstraints.getPatterns());
363 targetTypeBuilder.setFractionDigits(tConstraints.getFractionDigits());
365 return targetTypeBuilder;
368 private TypeDefinitionBuilder getTypeDefinitionBuilderFromDirtyNode(
369 final TypeAwareBuilder nodeToResolve,
370 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
371 final ModuleBuilder module) {
373 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
374 final QName unknownTypeQName = unknownType.getQName();
376 // search for module which contains referenced typedef
377 final ModuleBuilder dependentModule = findDependentModule(modules,
378 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
380 final TypeDefinitionBuilder lookedUpBuilder = findTypeDefinitionBuilder(
381 nodeToResolve.getPath(), dependentModule,
382 unknownTypeQName.getLocalName(), module.getName(),
383 nodeToResolve.getLine());
385 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
386 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
387 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
388 lookedUpBuilderCopy, modules, dependentModule);
392 private TypeDefinitionBuilder getUnionBuilder(
393 final TypeAwareBuilder nodeToResolve,
394 final UnknownType unknownType,
395 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
396 final ModuleBuilder module) {
398 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
399 if (baseTypeToResolve != null
400 && !(baseTypeToResolve instanceof UnknownType)) {
401 return (TypeDefinitionBuilder) nodeToResolve;
404 final QName unknownTypeQName = unknownType.getQName();
405 // search for module which contains referenced typedef
406 final ModuleBuilder dependentModule = findDependentModule(modules,
407 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
408 final TypeDefinitionBuilder lookedUpBuilder = findTypeDefinitionBuilder(
409 nodeToResolve.getPath(), dependentModule,
410 unknownTypeQName.getLocalName(), module.getName(),
411 nodeToResolve.getLine());
413 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
414 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
415 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
416 lookedUpBuilderCopy, modules, dependentModule);
420 private TypeDefinitionBuilder copyTypedefBuilder(
421 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
422 if (old instanceof UnionTypeBuilder) {
423 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
424 final UnionTypeBuilder newUnion = new UnionTypeBuilder(
426 for (TypeDefinition<?> td : oldUnion.getTypes()) {
427 newUnion.setType(td);
429 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
430 newUnion.setTypedef(copyTypedefBuilder(tdb, true));
432 newUnion.setPath(old.getPath());
436 final QName oldName = old.getQName();
437 final QName newName = new QName(oldName.getNamespace(),
438 oldName.getRevision(), oldName.getPrefix(),
439 oldName.getLocalName());
440 final TypeDefinitionBuilder tdb = new TypeDefinitionBuilderImpl(
441 newName, old.getLine());
443 tdb.setRanges(old.getRanges());
444 tdb.setLengths(old.getLengths());
445 tdb.setPatterns(old.getPatterns());
446 tdb.setFractionDigits(old.getFractionDigits());
447 tdb.setPath(old.getPath());
449 final TypeDefinition<?> oldType = old.getType();
450 if (oldType == null) {
451 tdb.setTypedef(old.getTypedef());
453 tdb.setType(oldType);
456 if (!seekByTypedefBuilder) {
457 tdb.setDescription(old.getDescription());
458 tdb.setReference(old.getReference());
459 tdb.setStatus(old.getStatus());
460 tdb.setDefaultValue(old.getDefaultValue());
461 tdb.setUnits(old.getUnits());
466 private TypeDefinitionBuilder resolveCopiedBuilder(
467 final TypeDefinitionBuilder copy,
468 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
469 final ModuleBuilder builder) {
471 if (copy instanceof UnionTypeBuilder) {
472 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
473 final List<TypeDefinition<?>> unionTypes = union.getTypes();
474 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
475 for (TypeDefinition<?> td : unionTypes) {
476 if (td instanceof UnknownType) {
477 final UnknownType unknownType = (UnknownType) td;
478 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
479 union, unknownType, modules, builder);
480 union.setTypedef(resolvedType);
481 toRemove.add(unknownType);
484 unionTypes.removeAll(toRemove);
489 final TypeDefinition<?> base = copy.getType();
490 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
491 if (base != null && !(base instanceof UnknownType)) {
493 } else if (base instanceof UnknownType) {
494 final UnknownType unknownType = (UnknownType) base;
495 final QName unknownTypeQName = unknownType.getQName();
496 final String unknownTypePrefix = unknownTypeQName.getPrefix();
497 final ModuleBuilder dependentModule = findDependentModule(modules,
498 builder, unknownTypePrefix, copy.getLine());
499 final TypeDefinitionBuilder utBuilder = getTypeDefinitionBuilderFromDirtyNode(
500 copy, modules, dependentModule);
501 copy.setTypedef(utBuilder);
503 } else if (base == null && baseTdb != null) {
504 // make a copy of baseTypeDef and call again
505 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
507 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
508 baseTdbCopy, modules, builder);
509 copy.setTypedef(baseTdbCopyResolved);
512 throw new YangParseException(copy.getLine(),
513 "Failed to resolve type " + copy.getQName().getLocalName());
517 private TypeConstraints findConstraints(
518 final TypeAwareBuilder nodeToResolve,
519 final TypeConstraints constraints,
520 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
521 final ModuleBuilder builder) {
522 // union type cannot be restricted
523 if (nodeToResolve instanceof UnionTypeBuilder) {
527 // if referenced type is UnknownType again, search recursively with
528 // current constraints
529 final TypeDefinition<?> referencedType = nodeToResolve.getType();
530 List<RangeConstraint> ranges = Collections.emptyList();
531 List<LengthConstraint> lengths = Collections.emptyList();
532 List<PatternConstraint> patterns = Collections.emptyList();
533 Integer fractionDigits = null;
534 if (referencedType == null) {
535 final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef();
536 ranges = tdb.getRanges();
537 constraints.addRanges(ranges);
538 lengths = tdb.getLengths();
539 constraints.addLengths(lengths);
540 patterns = tdb.getPatterns();
541 constraints.addPatterns(patterns);
542 fractionDigits = tdb.getFractionDigits();
543 constraints.setFractionDigits(fractionDigits);
545 } else if (referencedType instanceof ExtendedType) {
546 final ExtendedType ext = (ExtendedType) referencedType;
547 ranges = ext.getRanges();
548 constraints.addRanges(ranges);
549 lengths = ext.getLengths();
550 constraints.addLengths(lengths);
551 patterns = ext.getPatterns();
552 constraints.addPatterns(patterns);
553 fractionDigits = ext.getFractionDigits();
554 constraints.setFractionDigits(fractionDigits);
555 return findConstraints(
556 findTypeDefinitionBuilder(nodeToResolve.getPath(), builder,
557 ext.getQName().getLocalName(), builder.getName(),
558 nodeToResolve.getLine()), constraints, modules,
560 } else if (referencedType instanceof UnknownType) {
561 final UnknownType unknown = (UnknownType) referencedType;
562 ranges = unknown.getRangeStatements();
563 constraints.addRanges(ranges);
564 lengths = unknown.getLengthStatements();
565 constraints.addLengths(lengths);
566 patterns = unknown.getPatterns();
567 constraints.addPatterns(patterns);
568 fractionDigits = unknown.getFractionDigits();
569 constraints.setFractionDigits(fractionDigits);
571 String unknownTypePrefix = unknown.getQName().getPrefix();
572 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
573 unknownTypePrefix = builder.getPrefix();
575 final ModuleBuilder dependentModule = findDependentModule(modules,
576 builder, unknown.getQName().getPrefix(),
577 nodeToResolve.getLine());
578 final TypeDefinitionBuilder utBuilder = findTypeDefinitionBuilder(
579 nodeToResolve.getPath(), dependentModule, unknown
580 .getQName().getLocalName(), builder.getName(),
581 nodeToResolve.getLine());
582 return findConstraints(utBuilder, constraints, modules,
585 // HANDLE BASE YANG TYPE
586 mergeConstraints(referencedType, constraints);
592 * Search for type definition builder by name.
594 * @param dirtyNodeSchemaPath
595 * schema path of node which contains unresolved type
596 * @param dependentModule
597 * module which should contains referenced type
599 * name of type definition
600 * @param currentModuleName
601 * name of current module
603 * current line in yang model
606 private TypeDefinitionBuilder findTypeDefinitionBuilder(
607 SchemaPath dirtyNodeSchemaPath,
608 final ModuleBuilder dependentModule, final String typeName,
609 final String currentModuleName, final int line) {
610 final List<QName> path = dirtyNodeSchemaPath.getPath();
611 TypeDefinitionBuilder result = null;
613 Set<TypeDefinitionBuilder> typedefs = dependentModule
614 .getModuleTypedefs();
615 result = findTdb(typedefs, typeName);
617 if (result == null) {
618 Builder currentNode = null;
619 final List<String> currentPath = new ArrayList<String>();
620 currentPath.add(dependentModule.getName());
622 for (int i = 0; i < path.size(); i++) {
623 QName qname = path.get(i);
624 currentPath.add(qname.getLocalName());
625 currentNode = dependentModule.getModuleNode(currentPath);
627 if (currentNode instanceof RpcDefinitionBuilder) {
628 typedefs = ((RpcDefinitionBuilder) currentNode)
629 .getTypeDefinitions();
630 } else if (currentNode instanceof DataNodeContainerBuilder) {
631 typedefs = ((DataNodeContainerBuilder) currentNode)
632 .getTypeDefinitions();
634 typedefs = Collections.emptySet();
637 result = findTdb(typedefs, typeName);
638 if (result != null) {
644 if (result != null) {
647 throw new YangParseException(currentModuleName, line,
648 "Referenced type '" + typeName + "' not found.");
651 private TypeDefinitionBuilder findTdb(Set<TypeDefinitionBuilder> types,
653 for (TypeDefinitionBuilder td : types) {
654 if (td.getQName().getLocalName().equals(name)) {
662 * Pull restriction from referenced type and add them to given constraints
664 * @param referencedType
667 private void mergeConstraints(final TypeDefinition<?> referencedType,
668 final TypeConstraints constraints) {
670 if (referencedType instanceof DecimalTypeDefinition) {
671 constraints.addRanges(((DecimalTypeDefinition) referencedType)
672 .getRangeStatements());
674 .setFractionDigits(((DecimalTypeDefinition) referencedType)
675 .getFractionDigits());
676 } else if (referencedType instanceof IntegerTypeDefinition) {
677 constraints.addRanges(((IntegerTypeDefinition) referencedType)
678 .getRangeStatements());
679 } else if (referencedType instanceof StringTypeDefinition) {
680 constraints.addPatterns(((StringTypeDefinition) referencedType)
682 constraints.addLengths(((StringTypeDefinition) referencedType)
683 .getLengthStatements());
684 } else if (referencedType instanceof BinaryTypeDefinition) {
685 constraints.addLengths(((BinaryTypeDefinition) referencedType)
686 .getLengthConstraints());
691 * Go through all augment definitions and resolve them. This method also
692 * finds augment target node and add child nodes to it.
695 * all available modules
697 private void resolveAugments(
698 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
699 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
700 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
701 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
703 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
705 allModulesList.add(inner.getValue());
706 allModulesSet.add(inner.getValue());
710 for (int i = 0; i < allModulesList.size(); i++) {
711 final ModuleBuilder module = allModulesList.get(i);
712 // try to resolve augments in module
713 resolveAugment(modules, module);
714 // while all augments are not resolved
715 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
717 while (!(module.getAugmentsResolved() == module.getAugments()
719 ModuleBuilder nextModule = null;
720 // try resolve other module augments
722 nextModule = allModulesIterator.next();
723 resolveAugment(modules, nextModule);
724 } catch (NoSuchElementException e) {
725 throw new YangParseException(
726 "Failed to resolve augments in module '"
727 + module.getName() + "'.", e);
729 // then try to resolve first module again
730 resolveAugment(modules, module);
738 * all available modules
742 private void resolveAugment(
743 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
744 final ModuleBuilder module) {
745 if (module.getAugmentsResolved() < module.getAugments().size()) {
746 for (AugmentationSchemaBuilder augmentBuilder : module
749 if (!augmentBuilder.isResolved()) {
750 final SchemaPath augmentTargetSchemaPath = augmentBuilder
752 final List<QName> path = augmentTargetSchemaPath.getPath();
754 final QName qname = path.get(0);
755 String prefix = qname.getPrefix();
756 if (prefix == null) {
757 prefix = module.getPrefix();
760 DataSchemaNodeBuilder currentParent = null;
761 final ModuleBuilder dependentModule = findDependentModule(
762 modules, module, prefix, augmentBuilder.getLine());
763 for (DataSchemaNodeBuilder child : dependentModule
765 final QName childQName = child.getQName();
766 if (childQName.getLocalName().equals(
767 qname.getLocalName())) {
768 currentParent = child;
773 if (currentParent == null) {
777 for (int i = 1; i < path.size(); i++) {
778 final QName currentQName = path.get(i);
779 DataSchemaNodeBuilder newParent = null;
780 for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent)
782 final QName childQName = child.getQName();
783 if (childQName.getLocalName().equals(
784 currentQName.getLocalName())) {
789 if (newParent == null) {
790 break; // node not found, quit search
792 currentParent = newParent;
796 final QName currentQName = currentParent.getQName();
797 final QName lastAugmentPathElement = path
798 .get(path.size() - 1);
799 if (currentQName.getLocalName().equals(
800 lastAugmentPathElement.getLocalName())) {
802 if (currentParent instanceof ChoiceBuilder) {
803 ParserUtils.fillAugmentTarget(augmentBuilder,
804 (ChoiceBuilder) currentParent);
806 ParserUtils.fillAugmentTarget(augmentBuilder,
807 (DataNodeContainerBuilder) currentParent);
809 ((AugmentationTargetBuilder) currentParent)
810 .addAugmentation(augmentBuilder);
811 SchemaPath oldPath = currentParent.getPath();
812 augmentBuilder.setTargetPath(new SchemaPath(oldPath
813 .getPath(), oldPath.isAbsolute()));
814 augmentBuilder.setResolved(true);
815 module.augmentResolved();
824 * Go through identity statements defined in current module and resolve
825 * their 'base' statement if present.
830 * module being resolved
832 private void resolveIdentities(
833 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
834 final ModuleBuilder module) {
835 final Set<IdentitySchemaNodeBuilder> identities = module
837 for (IdentitySchemaNodeBuilder identity : identities) {
838 final String baseIdentityName = identity.getBaseIdentityName();
839 if (baseIdentityName != null) {
840 String baseIdentityPrefix = null;
841 String baseIdentityLocalName = null;
842 if (baseIdentityName.contains(":")) {
843 final String[] splitted = baseIdentityName.split(":");
844 baseIdentityPrefix = splitted[0];
845 baseIdentityLocalName = splitted[1];
847 baseIdentityPrefix = module.getPrefix();
848 baseIdentityLocalName = baseIdentityName;
850 final ModuleBuilder dependentModule = findDependentModule(
851 modules, module, baseIdentityPrefix, identity.getLine());
853 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
855 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
856 if (idBuilder.getQName().getLocalName()
857 .equals(baseIdentityLocalName)) {
858 identity.setBaseIdentity(idBuilder);
866 * Go through uses statements defined in current module and resolve their
872 * module being resolved
874 private void resolveUsesRefines(
875 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
876 final ModuleBuilder module) {
877 final Map<List<String>, UsesNodeBuilder> moduleUses = module
879 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
881 final List<String> key = entry.getKey();
882 final UsesNodeBuilder usesNode = entry.getValue();
883 final int line = usesNode.getLine();
885 final String groupingName = key.get(key.size() - 1);
887 for (RefineHolder refine : usesNode.getRefines()) {
888 SchemaNodeBuilder refineTarget = getRefineNodeBuilderCopy(
889 groupingName, refine, modules, module);
890 ParserUtils.checkRefine(refineTarget, refine);
891 ParserUtils.refineDefault(refineTarget, refine, line);
892 if (refineTarget instanceof LeafSchemaNodeBuilder) {
893 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
894 ParserUtils.refineLeaf(leaf, refine, line);
895 usesNode.addRefineNode(leaf);
896 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
897 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
898 ParserUtils.refineContainer(container, refine, line);
899 usesNode.addRefineNode(container);
900 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
901 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
902 ParserUtils.refineList(list, refine, line);
903 usesNode.addRefineNode(list);
904 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
905 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) refineTarget;
906 ParserUtils.refineLeafList(leafList, refine, line);
907 usesNode.addRefineNode(leafList);
908 } else if (refineTarget instanceof ChoiceBuilder) {
909 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
910 ParserUtils.refineChoice(choice, refine, line);
911 usesNode.addRefineNode(choice);
912 } else if (refineTarget instanceof AnyXmlBuilder) {
913 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
914 ParserUtils.refineAnyxml(anyXml, refine, line);
915 usesNode.addRefineNode(anyXml);
916 } else if (refineTarget instanceof GroupingBuilder) {
917 usesNode.addRefineNode(refineTarget);
918 } else if (refineTarget instanceof TypeDefinitionBuilder) {
919 usesNode.addRefineNode(refineTarget);
926 * Find original builder of node to refine and return copy of this builder.
928 * We must create and use a copy of builder to preserve original builder
929 * state, because this object will be refined (modified) and later added to
930 * {@link UsesNodeBuilder}.
933 * @param groupingPath
934 * path to grouping which contains node to refine
936 * refine object containing informations about refine
941 * @return copy of node to be refined if it is present in grouping, null
944 private SchemaNodeBuilder getRefineNodeBuilderCopy(
945 final String groupingPath, final RefineHolder refine,
946 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
947 final ModuleBuilder module) {
948 Builder result = null;
949 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
950 refine, modules, module);
951 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
953 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
954 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
956 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
957 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
959 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
960 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
962 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
963 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
965 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
966 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
968 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
969 } else if (lookedUpBuilder instanceof GroupingBuilder) {
971 .copyGroupingBuilder((GroupingBuilder) lookedUpBuilder);
972 } else if (lookedUpBuilder instanceof TypeDefinitionBuilder) {
974 .copyTypedefBuilder((TypeDefinitionBuilderImpl) lookedUpBuilder);
976 throw new YangParseException(module.getName(), refine.getLine(),
977 "Target '" + refine.getName() + "' can not be refined");
979 return (SchemaNodeBuilder) result;
983 * Find builder of refine node.
985 * @param groupingPath
986 * path to grouping which contains node to refine
988 * object containing refine information
993 * @return Builder object of refine node if it is present in grouping, null
996 private Builder findRefineTargetBuilder(final String groupingPath,
997 final RefineHolder refine,
998 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
999 final ModuleBuilder module) {
1000 final String refineNodeName = refine.getName();
1001 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
1002 final List<String> builderPath = new ArrayList<String>();
1003 String prefix = null;
1004 for (QName qname : path.getPath()) {
1005 builderPath.add(qname.getLocalName());
1006 prefix = qname.getPrefix();
1008 if (prefix == null) {
1009 prefix = module.getPrefix();
1012 final ModuleBuilder dependentModule = findDependentModule(modules,
1013 module, prefix, refine.getLine());
1014 builderPath.add(0, dependentModule.getName());
1015 final GroupingBuilder builder = dependentModule
1016 .getGrouping(builderPath);
1018 Builder result = builder.getChildNode(refineNodeName);
1019 if (result == null) {
1020 Set<GroupingBuilder> grps = builder.getGroupings();
1021 for (GroupingBuilder gr : grps) {
1022 if (gr.getQName().getLocalName().equals(refineNodeName)) {
1028 if (result == null) {
1029 Set<TypeDefinitionBuilder> typedefs = builder.getTypeDefinitions();
1030 for (TypeDefinitionBuilder typedef : typedefs) {
1031 if (typedef.getQName().getLocalName().equals(refineNodeName)) {
1040 private QName findFullQName(
1041 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1042 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
1043 QName result = null;
1044 String baseString = idref.getBaseString();
1045 if (baseString.contains(":")) {
1046 String[] splittedBase = baseString.split(":");
1047 if (splittedBase.length > 2) {
1048 throw new YangParseException(module.getName(), idref.getLine(),
1049 "Failed to parse identityref base: " + baseString);
1051 String prefix = splittedBase[0];
1052 String name = splittedBase[1];
1053 ModuleBuilder dependentModule = findDependentModule(modules,
1054 module, prefix, idref.getLine());
1055 result = new QName(dependentModule.getNamespace(),
1056 dependentModule.getRevision(), prefix, name);
1058 result = new QName(module.getNamespace(), module.getRevision(),
1059 module.getPrefix(), baseString);
1064 private void resolveUnknownNodes(
1065 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1066 final ModuleBuilder module) {
1067 for (UnknownSchemaNodeBuilder usnb : module.getUnknownNodes()) {
1068 QName nodeType = usnb.getNodeType();
1069 if (nodeType.getNamespace() == null
1070 || nodeType.getRevision() == null) {
1072 ModuleBuilder dependentModule = findDependentModule(
1073 modules, module, nodeType.getPrefix(),
1075 QName newNodeType = new QName(
1076 dependentModule.getNamespace(),
1077 dependentModule.getRevision(),
1078 nodeType.getPrefix(), nodeType.getLocalName());
1079 usnb.setNodeType(newNodeType);
1080 } catch (YangParseException e) {
1081 logger.debug(module.getName(), usnb.getLine(),
1082 "Failed to find unknown node type: " + nodeType);
1089 * Find dependent module based on given prefix
1092 * all available modules
1096 * target module prefix
1098 * current line in yang model
1101 private ModuleBuilder findDependentModule(
1102 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1103 final ModuleBuilder module, final String prefix, final int line) {
1104 ModuleBuilder dependentModule = null;
1105 Date dependentModuleRevision = null;
1107 if (prefix.equals(module.getPrefix())) {
1108 dependentModule = module;
1110 final ModuleImport dependentModuleImport = ParserUtils
1111 .getModuleImport(module, prefix);
1112 if (dependentModuleImport == null) {
1113 throw new YangParseException(module.getName(), line,
1114 "No import found with prefix '" + prefix + "'.");
1116 final String dependentModuleName = dependentModuleImport
1118 dependentModuleRevision = dependentModuleImport.getRevision();
1120 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1121 .get(dependentModuleName);
1122 if (moduleBuildersByRevision == null) {
1123 throw new YangParseException(module.getName(), line,
1124 "Failed to find dependent module '"
1125 + dependentModuleName + "'.");
1127 if (dependentModuleRevision == null) {
1128 dependentModule = moduleBuildersByRevision.lastEntry()
1131 dependentModule = moduleBuildersByRevision
1132 .get(dependentModuleRevision);
1136 if (dependentModule == null) {
1137 throw new YangParseException(module.getName(), line,
1138 "Failed to find dependent module with prefix '" + prefix
1139 + "' and revision '" + dependentModuleRevision
1142 return dependentModule;