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;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Date;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.LinkedHashMap;
23 import java.util.LinkedHashSet;
24 import java.util.List;
26 import java.util.NoSuchElementException;
28 import java.util.TreeMap;
30 import org.antlr.v4.runtime.ANTLRInputStream;
31 import org.antlr.v4.runtime.CommonTokenStream;
32 import org.antlr.v4.runtime.tree.ParseTree;
33 import org.antlr.v4.runtime.tree.ParseTreeWalker;
34 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
36 import org.opendaylight.controller.yang.common.QName;
37 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
38 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
39 import org.opendaylight.controller.yang.model.api.Module;
40 import org.opendaylight.controller.yang.model.api.ModuleImport;
41 import org.opendaylight.controller.yang.model.api.MustDefinition;
42 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
43 import org.opendaylight.controller.yang.model.api.RpcDefinition;
44 import org.opendaylight.controller.yang.model.api.SchemaContext;
45 import org.opendaylight.controller.yang.model.api.SchemaPath;
46 import org.opendaylight.controller.yang.model.api.TypeDefinition;
47 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
49 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
50 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
51 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
52 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
53 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
54 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
55 import org.opendaylight.controller.yang.model.util.ExtendedType;
56 import org.opendaylight.controller.yang.model.util.IdentityrefType;
57 import org.opendaylight.controller.yang.model.util.UnknownType;
58 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
59 import org.opendaylight.controller.yang.parser.builder.api.AugmentationTargetBuilder;
60 import org.opendaylight.controller.yang.parser.builder.api.Builder;
61 import org.opendaylight.controller.yang.parser.builder.api.ChildNodeBuilder;
62 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
63 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
64 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
65 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
66 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
67 import org.opendaylight.controller.yang.parser.builder.impl.AnyXmlBuilder;
68 import org.opendaylight.controller.yang.parser.builder.impl.ChoiceBuilder;
69 import org.opendaylight.controller.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
70 import org.opendaylight.controller.yang.parser.builder.impl.IdentitySchemaNodeBuilder;
71 import org.opendaylight.controller.yang.parser.builder.impl.IdentityrefTypeBuilder;
72 import org.opendaylight.controller.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
73 import org.opendaylight.controller.yang.parser.builder.impl.LeafSchemaNodeBuilder;
74 import org.opendaylight.controller.yang.parser.builder.impl.ListSchemaNodeBuilder;
75 import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
76 import org.opendaylight.controller.yang.parser.builder.impl.TypedefBuilder;
77 import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
78 import org.opendaylight.controller.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
79 import org.opendaylight.controller.yang.parser.util.ModuleDependencySort;
80 import org.opendaylight.controller.yang.parser.util.ParserUtils;
81 import org.opendaylight.controller.yang.parser.util.RefineHolder;
82 import org.opendaylight.controller.yang.parser.util.TypeConstraints;
83 import org.opendaylight.controller.yang.parser.util.YangParseException;
84 import org.opendaylight.controller.yang.validator.YangModelBasicValidator;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
88 public class YangParserImpl implements YangModelParser {
90 private static final Logger logger = LoggerFactory
91 .getLogger(YangParserImpl.class);
94 public Set<Module> parseYangModels(final List<File> yangFiles) {
95 if (yangFiles != null) {
96 final List<InputStream> inputStreams = new ArrayList<InputStream>();
98 for (final File yangFile : yangFiles) {
100 inputStreams.add(new FileInputStream(yangFile));
101 } catch (FileNotFoundException e) {
102 logger.warn("Exception while reading yang file: "
103 + yangFile.getName(), e);
106 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(inputStreams);
107 return build(modules);
109 return Collections.emptySet();
113 public Set<Module> parseYangModelsFromStreams(
114 final List<InputStream> yangModelStreams) {
115 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
116 return build(modules);
120 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
121 return new SchemaContextImpl(modules);
124 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
125 final List<InputStream> yangFileStreams) {
126 //Linked Hash Map MUST be used because Linked Hash Map preserves ORDER of items stored in map.
127 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new LinkedHashMap<String, TreeMap<Date, ModuleBuilder>>();
128 final ParseTreeWalker walker = new ParseTreeWalker();
129 final List<ParseTree> trees = parseStreams(yangFileStreams);
130 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
133 new YangModelBasicValidator(walker).validate(trees);
135 YangParserListenerImpl yangModelParser = null;
136 for (int i = 0; i < trees.size(); i++) {
137 yangModelParser = new YangParserListenerImpl();
138 walker.walk(yangModelParser, trees.get(i));
139 builders[i] = yangModelParser.getModuleBuilder();
142 // module dependency graph sorted
143 List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
145 for (ModuleBuilder builder : sorted) {
146 final String builderName = builder.getName();
147 Date builderRevision = builder.getRevision();
148 if (builderRevision == null) {
149 builderRevision = new Date(0L);
151 TreeMap<Date, ModuleBuilder> builderByRevision = modules
153 if (builderByRevision == null) {
154 builderByRevision = new TreeMap<Date, ModuleBuilder>();
156 builderByRevision.put(builderRevision, builder);
157 modules.put(builderName, builderByRevision);
162 private List<ParseTree> parseStreams(final List<InputStream> yangStreams) {
163 final List<ParseTree> trees = new ArrayList<ParseTree>();
164 for (InputStream yangStream : yangStreams) {
165 trees.add(parseStream(yangStream));
170 private ParseTree parseStream(final InputStream yangStream) {
171 ParseTree result = null;
173 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
174 final YangLexer lexer = new YangLexer(input);
175 final CommonTokenStream tokens = new CommonTokenStream(lexer);
176 final YangParser parser = new YangParser(tokens);
177 result = parser.yang();
178 } catch (IOException e) {
179 logger.warn("Exception while reading yang file: " + yangStream, e);
184 private Set<Module> build(
185 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
186 // fix unresolved nodes
187 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
189 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
191 final ModuleBuilder moduleBuilder = childEntry.getValue();
192 fixUnresolvedNodes(modules, moduleBuilder);
195 resolveAugments(modules);
198 // Linked Hash Set MUST be used otherwise the Set will not maintain order!
199 // http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashSet.html
200 final Set<Module> result = new LinkedHashSet<Module>();
201 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
203 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
204 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
206 final ModuleBuilder moduleBuilder = childEntry.getValue();
207 final Module module = moduleBuilder.build();
208 modulesByRevision.put(childEntry.getKey(), module);
215 private void fixUnresolvedNodes(
216 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
217 final ModuleBuilder builder) {
218 resolveDirtyNodes(modules, builder);
219 resolveIdentities(modules, builder);
220 resolveUses(modules, builder);
221 resolveUnknownNodes(modules, builder);
225 * Search for dirty nodes (node which contains UnknownType) and resolve
229 * all available modules
233 private void resolveDirtyNodes(
234 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
235 final ModuleBuilder module) {
236 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
238 if (!dirtyNodes.isEmpty()) {
239 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
242 final TypeAwareBuilder nodeToResolve = entry.getValue();
243 // different handling for union types
244 if (nodeToResolve instanceof UnionTypeBuilder) {
245 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
246 final List<TypeDefinition<?>> unionTypes = union.getTypes();
247 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
248 for (TypeDefinition<?> td : unionTypes) {
249 if (td instanceof UnknownType) {
250 final UnknownType unknownType = (UnknownType) td;
251 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
252 nodeToResolve, unknownType, modules, module);
253 union.setType(resolvedType);
254 toRemove.add(unknownType);
257 unionTypes.removeAll(toRemove);
258 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
259 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
261 nodeToResolve.setType(new IdentityrefType(findFullQName(
262 modules, module, idref), idref.getPath()));
264 final TypeDefinitionBuilder resolvedType = resolveType(
265 nodeToResolve, modules, module);
266 nodeToResolve.setType(resolvedType);
272 private TypeDefinitionBuilder resolveType(
273 final TypeAwareBuilder typeToResolve,
274 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
275 final ModuleBuilder builder) {
276 final TypeConstraints constraints = new TypeConstraints();
278 final TypeDefinitionBuilder targetType = getTypedefBuilder(
279 typeToResolve, modules, builder);
280 final TypeConstraints tConstraints = findConstraints(typeToResolve,
281 constraints, modules, builder);
282 targetType.setRanges(tConstraints.getRange());
283 targetType.setLengths(tConstraints.getLength());
284 targetType.setPatterns(tConstraints.getPatterns());
285 targetType.setFractionDigits(tConstraints.getFractionDigits());
290 private TypeDefinitionBuilder resolveTypeUnion(
291 final TypeAwareBuilder typeToResolve,
292 final UnknownType unknownType,
293 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
294 final ModuleBuilder builder) {
295 final TypeConstraints constraints = new TypeConstraints();
297 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
298 unknownType, modules, builder);
299 final TypeConstraints tConstraints = findConstraints(typeToResolve,
300 constraints, modules, builder);
301 targetType.setRanges(tConstraints.getRange());
302 targetType.setLengths(tConstraints.getLength());
303 targetType.setPatterns(tConstraints.getPatterns());
304 targetType.setFractionDigits(tConstraints.getFractionDigits());
309 private TypeDefinitionBuilder getTypedefBuilder(
310 final TypeAwareBuilder nodeToResolve,
311 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
312 final ModuleBuilder builder) {
314 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
315 if (nodeToResolveBase != null
316 && !(nodeToResolveBase instanceof UnknownType)) {
317 return (TypeDefinitionBuilder) nodeToResolve;
320 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
321 final QName unknownTypeQName = unknownType.getQName();
323 // search for module which contains referenced typedef
324 final ModuleBuilder dependentModule = findDependentModule(modules,
325 builder, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
326 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
327 dependentModule, unknownTypeQName.getLocalName(),
328 builder.getName(), nodeToResolve.getLine());
330 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
331 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
332 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
333 lookedUpBuilderCopy, modules, dependentModule);
337 private TypeDefinitionBuilder getUnionBuilder(
338 final TypeAwareBuilder nodeToResolve,
339 final UnknownType unknownType,
340 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
341 final ModuleBuilder module) {
343 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
344 if (baseTypeToResolve != null
345 && !(baseTypeToResolve instanceof UnknownType)) {
346 return (TypeDefinitionBuilder) nodeToResolve;
349 final QName unknownTypeQName = unknownType.getQName();
350 // search for module which contains referenced typedef
351 final ModuleBuilder dependentModule = findDependentModule(modules,
352 module, unknownTypeQName.getPrefix(), nodeToResolve.getLine());
353 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
354 dependentModule, unknownTypeQName.getLocalName(),
355 module.getName(), nodeToResolve.getLine());
357 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
358 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
359 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
360 lookedUpBuilderCopy, modules, dependentModule);
364 private TypeDefinitionBuilder copyTypedefBuilder(
365 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
366 if (old instanceof UnionTypeBuilder) {
367 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
368 final UnionTypeBuilder newUnion = new UnionTypeBuilder(
369 oldUnion.getActualPath(), oldUnion.getNamespace(),
370 oldUnion.getRevision(), old.getLine());
371 for (TypeDefinition<?> td : oldUnion.getTypes()) {
372 newUnion.setType(td);
374 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
375 newUnion.setType(copyTypedefBuilder(tdb, true));
380 final QName oldName = old.getQName();
381 final QName newName = new QName(oldName.getNamespace(),
382 oldName.getRevision(), oldName.getPrefix(),
383 oldName.getLocalName());
384 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName,
387 tdb.setRanges(old.getRanges());
388 tdb.setLengths(old.getLengths());
389 tdb.setPatterns(old.getPatterns());
390 tdb.setFractionDigits(old.getFractionDigits());
391 tdb.setPath(old.getPath());
393 final TypeDefinition<?> oldType = old.getType();
394 if (oldType == null) {
395 tdb.setType(old.getTypedef());
397 tdb.setType(oldType);
400 if (!seekByTypedefBuilder) {
401 tdb.setDescription(old.getDescription());
402 tdb.setReference(old.getReference());
403 tdb.setStatus(old.getStatus());
404 tdb.setDefaultValue(old.getDefaultValue());
405 tdb.setUnits(old.getUnits());
410 private TypeDefinitionBuilder resolveCopiedBuilder(
411 final TypeDefinitionBuilder copy,
412 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
413 final ModuleBuilder builder) {
415 if (copy instanceof UnionTypeBuilder) {
416 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
417 final List<TypeDefinition<?>> unionTypes = union.getTypes();
418 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
419 for (TypeDefinition<?> td : unionTypes) {
420 if (td instanceof UnknownType) {
421 final UnknownType unknownType = (UnknownType) td;
422 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
423 union, unknownType, modules, builder);
424 union.setType(resolvedType);
425 toRemove.add(unknownType);
428 unionTypes.removeAll(toRemove);
433 final TypeDefinition<?> base = copy.getType();
434 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
435 if (base != null && !(base instanceof UnknownType)) {
437 } else if (base instanceof UnknownType) {
438 final UnknownType unknownType = (UnknownType) base;
439 final QName unknownTypeQName = unknownType.getQName();
440 final String unknownTypePrefix = unknownTypeQName.getPrefix();
441 final ModuleBuilder dependentModule = findDependentModule(modules,
442 builder, unknownTypePrefix, copy.getLine());
443 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
444 modules, dependentModule);
445 copy.setType(utBuilder);
447 } else if (base == null && baseTdb != null) {
448 // make a copy of baseTypeDef and call again
449 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
451 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
452 baseTdbCopy, modules, builder);
453 copy.setType(baseTdbCopyResolved);
456 throw new IllegalStateException("Failed to resolve type "
457 + copy.getQName().getLocalName());
461 private TypeDefinitionBuilder findTypedefBuilder(
462 final QName unknownTypeQName,
463 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
464 final ModuleBuilder builder, int line) {
465 // search for module which contains referenced typedef
466 final ModuleBuilder dependentModule = findDependentModule(modules,
467 builder, unknownTypeQName.getPrefix(), line);
468 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
469 dependentModule, unknownTypeQName.getLocalName(),
470 builder.getName(), line);
471 return copyTypedefBuilder(lookedUpBuilder, true);
474 private TypeConstraints findConstraints(
475 final TypeAwareBuilder nodeToResolve,
476 final TypeConstraints constraints,
477 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
478 final ModuleBuilder builder) {
479 // union type cannot be restricted
480 if (nodeToResolve instanceof UnionTypeBuilder) {
484 // if referenced type is UnknownType again, search recursively with
485 // current constraints
486 final TypeDefinition<?> referencedType = nodeToResolve.getType();
487 List<RangeConstraint> ranges = Collections.emptyList();
488 List<LengthConstraint> lengths = Collections.emptyList();
489 List<PatternConstraint> patterns = Collections.emptyList();
490 Integer fractionDigits = null;
491 if (referencedType == null) {
492 final TypeDefinitionBuilder tdb = nodeToResolve.getTypedef();
493 ranges = tdb.getRanges();
494 constraints.addRanges(ranges);
495 lengths = tdb.getLengths();
496 constraints.addLengths(lengths);
497 patterns = tdb.getPatterns();
498 constraints.addPatterns(patterns);
499 fractionDigits = tdb.getFractionDigits();
500 constraints.setFractionDigits(fractionDigits);
502 } else if (referencedType instanceof ExtendedType) {
503 final ExtendedType ext = (ExtendedType) referencedType;
504 ranges = ext.getRanges();
505 constraints.addRanges(ranges);
506 lengths = ext.getLengths();
507 constraints.addLengths(lengths);
508 patterns = ext.getPatterns();
509 constraints.addPatterns(patterns);
510 fractionDigits = ext.getFractionDigits();
511 constraints.setFractionDigits(fractionDigits);
512 return findConstraints(
513 findTypedefBuilder(ext.getQName(), modules, builder,
514 nodeToResolve.getLine()), constraints, modules,
516 } else if (referencedType instanceof UnknownType) {
517 final UnknownType unknown = (UnknownType) referencedType;
518 ranges = unknown.getRangeStatements();
519 constraints.addRanges(ranges);
520 lengths = unknown.getLengthStatements();
521 constraints.addLengths(lengths);
522 patterns = unknown.getPatterns();
523 constraints.addPatterns(patterns);
524 fractionDigits = unknown.getFractionDigits();
525 constraints.setFractionDigits(fractionDigits);
527 String unknownTypePrefix = unknown.getQName().getPrefix();
528 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
529 unknownTypePrefix = builder.getPrefix();
531 final ModuleBuilder dependentModule = findDependentModule(modules,
532 builder, unknown.getQName().getPrefix(),
533 nodeToResolve.getLine());
534 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
535 unknown.getQName(), modules, builder,
536 nodeToResolve.getLine());
537 return findConstraints(utBuilder, constraints, modules,
540 // HANDLE BASE YANG TYPE
541 mergeConstraints(referencedType, constraints);
547 * Go through all typedef statements from given module and search for one
551 * typedef statements to search
553 * name of searched typedef
554 * @return typedef with name equals to given name
556 private TypeDefinitionBuilder findTypedefBuilderByName(
557 final ModuleBuilder dependentModule, final String name,
558 final String currentModuleName, final int line) {
559 TypeDefinitionBuilder result = null;
560 final Set<TypeDefinitionBuilder> typedefs = dependentModule
561 .getModuleTypedefs();
562 for (TypeDefinitionBuilder td : typedefs) {
563 if (td.getQName().getLocalName().equals(name)) {
568 if (result == null) {
569 throw new YangParseException(currentModuleName, line,
570 "Target module '" + dependentModule.getName()
571 + "' does not contain typedef '" + name + "'.");
577 * Pull restriction from referenced type and add them to given constraints
579 * @param referencedType
582 private void mergeConstraints(final TypeDefinition<?> referencedType,
583 final TypeConstraints constraints) {
585 if (referencedType instanceof DecimalTypeDefinition) {
586 constraints.addRanges(((DecimalTypeDefinition) referencedType)
587 .getRangeStatements());
589 .setFractionDigits(((DecimalTypeDefinition) referencedType)
590 .getFractionDigits());
591 } else if (referencedType instanceof IntegerTypeDefinition) {
592 constraints.addRanges(((IntegerTypeDefinition) referencedType)
593 .getRangeStatements());
594 } else if (referencedType instanceof StringTypeDefinition) {
595 constraints.addPatterns(((StringTypeDefinition) referencedType)
597 constraints.addLengths(((StringTypeDefinition) referencedType)
598 .getLengthStatements());
599 } else if (referencedType instanceof BinaryTypeDefinition) {
600 constraints.addLengths(((BinaryTypeDefinition) referencedType)
601 .getLengthConstraints());
606 * Go through all augmentation definitions and resolve them. This method
607 * also finds referenced node and add child nodes to it.
610 * all available modules
612 private void resolveAugments(
613 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
614 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
615 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
616 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
618 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
620 allModulesList.add(inner.getValue());
621 allModulesSet.add(inner.getValue());
625 for (int i = 0; i < allModulesList.size(); i++) {
626 final ModuleBuilder module = allModulesList.get(i);
627 // try to resolve augments in module
628 resolveAugment(modules, module);
629 // while all augments are not resolved
630 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
632 while (!(module.getAugmentsResolved() == module.getAddedAugments()
634 ModuleBuilder nextModule = null;
635 // try resolve other module augments
637 nextModule = allModulesIterator.next();
638 resolveAugment(modules, nextModule);
639 } catch (NoSuchElementException e) {
640 throw new YangParseException(
641 "Failed to resolve augments in module '"
642 + module.getName() + "'.", e);
644 // then try to resolve first module again
645 resolveAugment(modules, module);
653 * all available modules
657 private void resolveAugment(
658 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
659 final ModuleBuilder module) {
660 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
661 for (AugmentationSchemaBuilder augmentBuilder : module
662 .getAddedAugments()) {
664 if (!augmentBuilder.isResolved()) {
665 final SchemaPath augmentTargetSchemaPath = augmentBuilder
667 final List<QName> path = augmentTargetSchemaPath.getPath();
670 final QName qname = path.get(i);
671 String prefix = qname.getPrefix();
672 if (prefix == null) {
673 prefix = module.getPrefix();
676 DataSchemaNodeBuilder currentParent = null;
677 final ModuleBuilder dependentModule = findDependentModule(
678 modules, module, prefix, augmentBuilder.getLine());
679 for (DataSchemaNodeBuilder child : dependentModule
681 final QName childQName = child.getQName();
682 if (childQName.getLocalName().equals(
683 qname.getLocalName())) {
684 currentParent = child;
690 for (; i < path.size(); i++) {
691 final QName currentQName = path.get(i);
692 DataSchemaNodeBuilder newParent = null;
693 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
695 final QName childQName = child.getQName();
696 if (childQName.getLocalName().equals(
697 currentQName.getLocalName())) {
702 if (newParent == null) {
703 break; // node not found, quit search
705 currentParent = newParent;
709 final QName currentQName = currentParent.getQName();
710 final QName lastAugmentPathElement = path
711 .get(path.size() - 1);
712 if (currentQName.getLocalName().equals(
713 lastAugmentPathElement.getLocalName())) {
714 ParserUtils.fillAugmentTarget(augmentBuilder,
715 (ChildNodeBuilder) currentParent);
716 ((AugmentationTargetBuilder) currentParent)
717 .addAugmentation(augmentBuilder);
718 SchemaPath oldPath = currentParent.getPath();
719 augmentBuilder.setTargetPath(new SchemaPath(oldPath
720 .getPath(), oldPath.isAbsolute()));
721 augmentBuilder.setResolved(true);
722 module.augmentResolved();
731 * Go through identity statements defined in current module and resolve
732 * their 'base' statement if present.
737 * module being resolved
739 private void resolveIdentities(
740 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
741 final ModuleBuilder module) {
742 final Set<IdentitySchemaNodeBuilder> identities = module
743 .getAddedIdentities();
744 for (IdentitySchemaNodeBuilder identity : identities) {
745 final String baseIdentityName = identity.getBaseIdentityName();
746 if (baseIdentityName != null) {
747 String baseIdentityPrefix = null;
748 String baseIdentityLocalName = null;
749 if (baseIdentityName.contains(":")) {
750 final String[] splitted = baseIdentityName.split(":");
751 baseIdentityPrefix = splitted[0];
752 baseIdentityLocalName = splitted[1];
754 baseIdentityPrefix = module.getPrefix();
755 baseIdentityLocalName = baseIdentityName;
757 final ModuleBuilder dependentModule = findDependentModule(
758 modules, module, baseIdentityPrefix, identity.getLine());
760 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
761 .getAddedIdentities();
762 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
763 if (idBuilder.getQName().getLocalName()
764 .equals(baseIdentityLocalName)) {
765 identity.setBaseIdentity(idBuilder);
773 * Go through uses statements defined in current module and resolve their
779 * module being resolved
781 private void resolveUses(
782 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
783 final ModuleBuilder module) {
784 final Map<List<String>, UsesNodeBuilder> moduleUses = module
785 .getAddedUsesNodes();
786 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
788 final List<String> key = entry.getKey();
789 final UsesNodeBuilder usesNode = entry.getValue();
791 final String groupingName = key.get(key.size() - 1);
793 for (RefineHolder refine : usesNode.getRefines()) {
795 final String defaultStr = refine.getDefaultStr();
796 final Boolean mandatory = refine.isMandatory();
797 final MustDefinition must = refine.getMust();
798 final Boolean presence = refine.isPresence();
799 final Integer min = refine.getMinElements();
800 final Integer max = refine.getMaxElements();
801 final List<UnknownSchemaNodeBuilder> unknownNodes = refine
804 Builder refineTarget = getRefineTargetBuilder(groupingName,
805 refine, modules, module);
806 if (refineTarget instanceof LeafSchemaNodeBuilder) {
807 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
808 if (defaultStr != null && !("".equals(defaultStr))) {
809 leaf.setDefaultStr(defaultStr);
811 if (mandatory != null) {
812 leaf.getConstraints().setMandatory(mandatory);
815 leaf.getConstraints().addMustDefinition(must);
817 if (unknownNodes != null) {
818 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
819 leaf.addUnknownSchemaNode(unknown);
822 usesNode.addRefineNode(leaf);
823 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
824 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
825 if (presence != null) {
826 container.setPresence(presence);
829 container.getConstraints().addMustDefinition(must);
831 if (unknownNodes != null) {
832 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
833 container.addUnknownSchemaNode(unknown);
836 usesNode.addRefineNode(container);
837 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
838 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
840 list.getConstraints().addMustDefinition(must);
843 list.getConstraints().setMinElements(min);
846 list.getConstraints().setMaxElements(max);
848 if (unknownNodes != null) {
849 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
850 list.addUnknownSchemaNode(unknown);
853 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
854 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
855 groupingName, refine, modules, module);
857 leafList.getConstraints().addMustDefinition(must);
860 leafList.getConstraints().setMinElements(min);
863 leafList.getConstraints().setMaxElements(max);
865 if (unknownNodes != null) {
866 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
867 leafList.addUnknownSchemaNode(unknown);
870 } else if (refineTarget instanceof ChoiceBuilder) {
871 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
872 if (defaultStr != null) {
873 choice.setDefaultCase(defaultStr);
875 if (mandatory != null) {
876 choice.getConstraints().setMandatory(mandatory);
878 if (unknownNodes != null) {
879 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
880 choice.addUnknownSchemaNode(unknown);
883 } else if (refineTarget instanceof AnyXmlBuilder) {
884 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
885 if (mandatory != null) {
886 anyXml.getConstraints().setMandatory(mandatory);
889 anyXml.getConstraints().addMustDefinition(must);
891 if (unknownNodes != null) {
892 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
893 anyXml.addUnknownSchemaNode(unknown);
902 * Find original builder of refine node and return copy of this builder.
904 * @param groupingPath
905 * path to grouping which contains node to refine
907 * refine object containing informations about refine
912 * @return copy of Builder object of node to be refined if it is present in
913 * grouping, null otherwise
915 private Builder getRefineTargetBuilder(final String groupingPath,
916 final RefineHolder refine,
917 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
918 final ModuleBuilder module) {
919 Builder result = null;
920 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
921 refine, modules, module);
922 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
924 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
925 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
927 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
928 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
930 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
931 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
933 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
934 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
936 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
937 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
939 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
941 throw new YangParseException(module.getName(), refine.getLine(),
942 "Target '" + refine.getName() + "' can not be refined");
948 * Find builder of refine node.
950 * @param groupingPath
951 * path to grouping which contains node to refine
952 * @param refineNodeName
953 * name of node to be refined
958 * @return Builder object of refine node if it is present in grouping, null
961 private Builder findRefineTargetBuilder(final String groupingPath,
962 final RefineHolder refine,
963 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
964 final ModuleBuilder module) {
965 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
966 final List<String> builderPath = new ArrayList<String>();
967 String prefix = null;
968 for (QName qname : path.getPath()) {
969 builderPath.add(qname.getLocalName());
970 prefix = qname.getPrefix();
972 if (prefix == null) {
973 prefix = module.getPrefix();
976 final ModuleBuilder dependentModule = findDependentModule(modules,
977 module, prefix, refine.getLine());
978 builderPath.add(0, "grouping");
979 builderPath.add(0, dependentModule.getName());
980 final GroupingBuilder builder = (GroupingBuilder) dependentModule
981 .getNode(builderPath);
983 return builder.getChildNode(refine.getName());
986 private QName findFullQName(
987 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
988 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
990 String baseString = idref.getBaseString();
991 if (baseString.contains(":")) {
992 String[] splittedBase = baseString.split(":");
993 if (splittedBase.length > 2) {
994 throw new YangParseException(module.getName(), idref.getLine(),
995 "Failed to parse identityref base: " + baseString);
997 String prefix = splittedBase[0];
998 String name = splittedBase[1];
999 ModuleBuilder dependentModule = findDependentModule(modules,
1000 module, prefix, idref.getLine());
1001 result = new QName(dependentModule.getNamespace(),
1002 dependentModule.getRevision(), prefix, name);
1004 result = new QName(module.getNamespace(), module.getRevision(),
1005 module.getPrefix(), baseString);
1010 private void resolveUnknownNodes(
1011 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1012 final ModuleBuilder module) {
1013 for (UnknownSchemaNodeBuilder usnb : module.getAddedUnknownNodes()) {
1014 QName nodeType = usnb.getNodeType();
1015 if (nodeType.getNamespace() == null
1016 || nodeType.getRevision() == null) {
1018 ModuleBuilder dependentModule = findDependentModule(
1019 modules, module, nodeType.getPrefix(),
1021 QName newNodeType = new QName(
1022 dependentModule.getNamespace(),
1023 dependentModule.getRevision(),
1024 nodeType.getPrefix(), nodeType.getLocalName());
1025 usnb.setNodeType(newNodeType);
1026 } catch (YangParseException e) {
1027 logger.debug(module.getName(), usnb.getLine(),
1028 "Failed to find unknown node type: " + nodeType);
1035 * Find dependent module based on given prefix
1038 * all available modules
1042 * target module prefix
1045 private ModuleBuilder findDependentModule(
1046 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1047 final ModuleBuilder module, final String prefix, final int line) {
1048 ModuleBuilder dependentModule = null;
1049 Date dependentModuleRevision = null;
1051 if (prefix.equals(module.getPrefix())) {
1052 dependentModule = module;
1054 final ModuleImport dependentModuleImport = ParserUtils
1055 .getModuleImport(module, prefix);
1056 if (dependentModuleImport == null) {
1057 throw new YangParseException(module.getName(), line,
1058 "No import found with prefix '" + prefix + "'.");
1060 final String dependentModuleName = dependentModuleImport
1062 dependentModuleRevision = dependentModuleImport.getRevision();
1064 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1065 .get(dependentModuleName);
1066 if (moduleBuildersByRevision == null) {
1067 throw new YangParseException(module.getName(), line,
1068 "Failed to find dependent module '"
1069 + dependentModuleName + "'.");
1071 if (dependentModuleRevision == null) {
1072 dependentModule = moduleBuildersByRevision.lastEntry()
1075 dependentModule = moduleBuildersByRevision
1076 .get(dependentModuleRevision);
1080 if (dependentModule == null) {
1081 throw new YangParseException(module.getName(), line,
1082 "Failed to find dependent module with prefix '" + prefix
1083 + "' and revision '" + dependentModuleRevision
1086 return dependentModule;
1089 private static class SchemaContextImpl implements SchemaContext {
1090 private final Set<Module> modules;
1092 private SchemaContextImpl(final Set<Module> modules) {
1093 this.modules = modules;
1097 public Set<DataSchemaNode> getDataDefinitions() {
1098 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
1099 for (Module m : modules) {
1100 dataDefs.addAll(m.getChildNodes());
1106 public Set<Module> getModules() {
1111 public Set<NotificationDefinition> getNotifications() {
1112 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
1113 for (Module m : modules) {
1114 notifications.addAll(m.getNotifications());
1116 return notifications;
1120 public Set<RpcDefinition> getOperations() {
1121 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
1122 for (Module m : modules) {
1123 rpcs.addAll(m.getRpcs());
1129 public Set<ExtensionDefinition> getExtensions() {
1130 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
1131 for (Module m : modules) {
1132 extensions.addAll(m.getExtensionSchemaNodes());
1138 public Module findModuleByName(final String name, final Date revision) {
1140 for (final Module module : modules) {
1141 if (revision == null) {
1142 if (module.getName().equals(name)) {
1145 } else if (module.getName().equals(name)
1146 && module.getRevision().equals(revision)) {
1155 public Module findModuleByNamespace(final URI namespace) {
1156 if (namespace != null) {
1157 for (final Module module : modules) {
1158 if (module.getNamespace().equals(namespace)) {