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.model.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.List;
24 import java.util.NoSuchElementException;
26 import java.util.TreeMap;
28 import org.antlr.v4.runtime.ANTLRInputStream;
29 import org.antlr.v4.runtime.CommonTokenStream;
30 import org.antlr.v4.runtime.tree.ParseTree;
31 import org.antlr.v4.runtime.tree.ParseTreeWalker;
32 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
34 import org.opendaylight.controller.yang.common.QName;
35 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
36 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
37 import org.opendaylight.controller.yang.model.api.Module;
38 import org.opendaylight.controller.yang.model.api.ModuleImport;
39 import org.opendaylight.controller.yang.model.api.MustDefinition;
40 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
41 import org.opendaylight.controller.yang.model.api.RpcDefinition;
42 import org.opendaylight.controller.yang.model.api.SchemaContext;
43 import org.opendaylight.controller.yang.model.api.SchemaPath;
44 import org.opendaylight.controller.yang.model.api.TypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
46 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
47 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
48 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
49 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
50 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
51 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
52 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
53 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
54 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
55 import org.opendaylight.controller.yang.model.parser.builder.api.Builder;
56 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;
62 import org.opendaylight.controller.yang.model.parser.builder.impl.AnyXmlBuilder;
63 import org.opendaylight.controller.yang.model.parser.builder.impl.ChoiceBuilder;
64 import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchemaNodeBuilder;
65 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
66 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentityrefTypeBuilder;
67 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
68 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
69 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
70 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
71 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
72 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
73 import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder;
74 import org.opendaylight.controller.yang.model.parser.util.ParserUtils;
75 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
76 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
77 import org.opendaylight.controller.yang.model.parser.util.YangParseException;
78 import org.opendaylight.controller.yang.model.util.ExtendedType;
79 import org.opendaylight.controller.yang.model.util.IdentityrefType;
80 import org.opendaylight.controller.yang.model.util.UnknownType;
81 import org.opendaylight.controller.yang.model.validator.YangModelBasicValidator;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
85 public class YangModelParserImpl implements YangModelParser {
87 private static final Logger logger = LoggerFactory
88 .getLogger(YangModelParserImpl.class);
91 public Module parseYangModel(final String yangFile) {
92 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFile);
93 final Set<Module> result = build(modules);
94 return result.iterator().next();
98 public Set<Module> parseYangModels(final String... yangFiles) {
99 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFiles);
100 return build(modules);
104 public Set<Module> parseYangModelsFromStreams(
105 final InputStream... yangModelStreams) {
106 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
107 return build(modules);
111 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
112 return new SchemaContextImpl(modules);
115 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
116 final String... yangFiles) {
117 final InputStream[] streams = loadStreams(yangFiles);
118 Map<String, TreeMap<Date, ModuleBuilder>> result = Collections
121 if (streams != null) {
122 result = resolveModuleBuilders(streams);
123 closeStreams(streams);
128 private InputStream[] loadStreams(final String... yangFiles) {
129 final InputStream[] streams = new InputStream[yangFiles.length];
130 for (int i = 0; i < yangFiles.length; i++) {
131 final String yangFileName = yangFiles[i];
132 final File yangFile = new File(yangFileName);
134 streams[i] = new FileInputStream(yangFile);
135 } catch (FileNotFoundException e) {
136 logger.warn("Exception while reading yang stream: "
143 private void closeStreams(final InputStream[] streams) {
144 if (streams != null) {
145 for (int i = 0; i < streams.length; i++) {
147 if (streams[i] != null) {
150 } catch (IOException e) {
151 logger.warn("Exception while closing yang stream: "
158 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
159 final InputStream... yangFiles) {
160 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
161 final ParseTreeWalker walker = new ParseTreeWalker();
162 final List<ParseTree> trees = parseStreams(yangFiles);
163 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
166 new YangModelBasicValidator(walker).validate(trees);
168 YangModelParserListenerImpl yangModelParser = null;
169 for (int i = 0; i < trees.size(); i++) {
170 yangModelParser = new YangModelParserListenerImpl();
171 walker.walk(yangModelParser, trees.get(i));
172 builders[i] = yangModelParser.getModuleBuilder();
175 for (ModuleBuilder builder : builders) {
176 final String builderName = builder.getName();
177 Date builderRevision = builder.getRevision();
178 if (builderRevision == null) {
179 builderRevision = new Date(0L);
181 TreeMap<Date, ModuleBuilder> builderByRevision = modules
183 if (builderByRevision == null) {
184 builderByRevision = new TreeMap<Date, ModuleBuilder>();
186 builderByRevision.put(builderRevision, builder);
187 modules.put(builderName, builderByRevision);
192 private List<ParseTree> parseStreams(final InputStream... yangStreams) {
193 final List<ParseTree> trees = new ArrayList<ParseTree>();
194 for (InputStream yangStream : yangStreams) {
195 trees.add(parseStream(yangStream));
200 private ParseTree parseStream(final InputStream yangStream) {
201 ParseTree result = null;
203 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
204 final YangLexer lexer = new YangLexer(input);
205 final CommonTokenStream tokens = new CommonTokenStream(lexer);
206 final YangParser parser = new YangParser(tokens);
207 result = parser.yang();
208 } catch (IOException e) {
209 logger.warn("Exception while reading yang file: " + yangStream, e);
214 private Set<Module> build(
215 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
216 // fix unresolved nodes
217 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
219 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
221 final ModuleBuilder moduleBuilder = childEntry.getValue();
222 fixUnresolvedNodes(modules, moduleBuilder);
225 resolveAugments(modules);
228 final Set<Module> result = new HashSet<Module>();
229 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
231 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
232 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
234 final ModuleBuilder moduleBuilder = childEntry.getValue();
235 final Module module = moduleBuilder.build();
236 modulesByRevision.put(childEntry.getKey(), module);
243 private void fixUnresolvedNodes(
244 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
245 final ModuleBuilder builder) {
246 resolveDirtyNodes(modules, builder);
247 resolveIdentities(modules, builder);
248 resolveUses(modules, builder);
252 * Search for dirty nodes (node which contains UnknownType) and resolve
256 * all available modules
260 private void resolveDirtyNodes(
261 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
262 final ModuleBuilder module) {
263 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
265 if (!dirtyNodes.isEmpty()) {
266 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
269 final TypeAwareBuilder nodeToResolve = entry.getValue();
270 // different handling for union types
271 if (nodeToResolve instanceof UnionTypeBuilder) {
272 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
273 final List<TypeDefinition<?>> unionTypes = union.getTypes();
274 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
275 for (TypeDefinition<?> td : unionTypes) {
276 if (td instanceof UnknownType) {
277 final UnknownType unknownType = (UnknownType) td;
278 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
279 nodeToResolve, unknownType, modules, module);
280 union.setType(resolvedType);
281 toRemove.add(unknownType);
284 unionTypes.removeAll(toRemove);
285 } else if (nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
286 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder) nodeToResolve
288 nodeToResolve.setType(new IdentityrefType(findFullQName(
289 modules, module, idref), idref.getPath()));
291 final TypeDefinitionBuilder resolvedType = resolveType(
292 nodeToResolve, modules, module);
293 nodeToResolve.setType(resolvedType);
299 private TypeDefinitionBuilder resolveType(
300 final TypeAwareBuilder typeToResolve,
301 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
302 final ModuleBuilder builder) {
303 final TypeConstraints constraints = new TypeConstraints();
305 final TypeDefinitionBuilder targetType = getTypedefBuilder(
306 typeToResolve, modules, builder);
307 final TypeConstraints tConstraints = findConstraints(typeToResolve,
308 constraints, modules, builder);
309 targetType.setRanges(tConstraints.getRange());
310 targetType.setLengths(tConstraints.getLength());
311 targetType.setPatterns(tConstraints.getPatterns());
312 targetType.setFractionDigits(tConstraints.getFractionDigits());
317 private TypeDefinitionBuilder resolveTypeUnion(
318 final TypeAwareBuilder typeToResolve,
319 final UnknownType unknownType,
320 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
321 final ModuleBuilder builder) {
322 final TypeConstraints constraints = new TypeConstraints();
324 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
325 unknownType, modules, builder);
326 final TypeConstraints tConstraints = findConstraints(typeToResolve,
327 constraints, modules, builder);
328 targetType.setRanges(tConstraints.getRange());
329 targetType.setLengths(tConstraints.getLength());
330 targetType.setPatterns(tConstraints.getPatterns());
331 targetType.setFractionDigits(tConstraints.getFractionDigits());
336 private TypeDefinitionBuilder getTypedefBuilder(
337 final TypeAwareBuilder nodeToResolve,
338 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
339 final ModuleBuilder builder) {
341 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
342 if (nodeToResolveBase != null
343 && !(nodeToResolveBase instanceof UnknownType)) {
344 return (TypeDefinitionBuilder) nodeToResolve;
347 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
348 final QName unknownTypeQName = unknownType.getQName();
350 // search for module which contains referenced typedef
351 final ModuleBuilder dependentModule = findDependentModule(modules,
352 builder, unknownTypeQName.getPrefix());
353 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
354 dependentModule, unknownTypeQName.getLocalName());
356 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
357 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
358 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
359 lookedUpBuilderCopy, modules, dependentModule);
363 private TypeDefinitionBuilder getUnionBuilder(
364 final TypeAwareBuilder nodeToResolve,
365 final UnknownType unknownType,
366 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
367 final ModuleBuilder module) {
369 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
370 if (baseTypeToResolve != null
371 && !(baseTypeToResolve instanceof UnknownType)) {
372 return (TypeDefinitionBuilder) nodeToResolve;
375 final QName unknownTypeQName = unknownType.getQName();
376 // search for module which contains referenced typedef
377 final ModuleBuilder dependentModule = findDependentModule(modules,
378 module, unknownTypeQName.getPrefix());
379 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
380 dependentModule, unknownTypeQName.getLocalName());
382 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
383 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
384 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
385 lookedUpBuilderCopy, modules, dependentModule);
389 private TypeDefinitionBuilder copyTypedefBuilder(
390 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
391 if (old instanceof UnionTypeBuilder) {
392 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
393 final UnionTypeBuilder newUnion = new UnionTypeBuilder(
394 oldUnion.getActualPath(), oldUnion.getNamespace(),
395 oldUnion.getRevision());
396 for (TypeDefinition<?> td : oldUnion.getTypes()) {
397 newUnion.setType(td);
399 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
400 newUnion.setType(copyTypedefBuilder(tdb, true));
405 final QName oldName = old.getQName();
406 final QName newName = new QName(oldName.getNamespace(),
407 oldName.getRevision(), oldName.getPrefix(),
408 oldName.getLocalName());
409 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName);
411 tdb.setRanges(old.getRanges());
412 tdb.setLengths(old.getLengths());
413 tdb.setPatterns(old.getPatterns());
414 tdb.setFractionDigits(old.getFractionDigits());
416 final TypeDefinition<?> oldType = old.getType();
417 if (oldType == null) {
418 tdb.setType(old.getTypedef());
420 tdb.setType(oldType);
423 if (!seekByTypedefBuilder) {
424 tdb.setDescription(old.getDescription());
425 tdb.setReference(old.getReference());
426 tdb.setStatus(old.getStatus());
427 tdb.setDefaultValue(old.getDefaultValue());
428 tdb.setUnits(old.getUnits());
433 private TypeDefinitionBuilder resolveCopiedBuilder(
434 final TypeDefinitionBuilder copy,
435 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
436 final ModuleBuilder builder) {
438 if (copy instanceof UnionTypeBuilder) {
439 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
440 final List<TypeDefinition<?>> unionTypes = union.getTypes();
441 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
442 for (TypeDefinition<?> td : unionTypes) {
443 if (td instanceof UnknownType) {
444 final UnknownType unknownType = (UnknownType) td;
445 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
446 union, unknownType, modules, builder);
447 union.setType(resolvedType);
448 toRemove.add(unknownType);
451 unionTypes.removeAll(toRemove);
456 final TypeDefinition<?> base = copy.getType();
457 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
458 if (base != null && !(base instanceof UnknownType)) {
460 } else if (base instanceof UnknownType) {
461 final UnknownType unknownType = (UnknownType) base;
462 final QName unknownTypeQName = unknownType.getQName();
463 final String unknownTypePrefix = unknownTypeQName.getPrefix();
464 final ModuleBuilder dependentModule = findDependentModule(modules,
465 builder, unknownTypePrefix);
466 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
467 modules, dependentModule);
468 copy.setType(utBuilder);
470 } else if (base == null && baseTdb != null) {
471 // make a copy of baseTypeDef and call again
472 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
474 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
475 baseTdbCopy, modules, builder);
476 copy.setType(baseTdbCopyResolved);
479 throw new IllegalStateException("Failed to resolve type "
480 + copy.getQName().getLocalName());
484 private TypeDefinitionBuilder findTypedefBuilder(
485 final QName unknownTypeQName,
486 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
487 final ModuleBuilder builder) {
488 // search for module which contains referenced typedef
489 final ModuleBuilder dependentModule = findDependentModule(modules,
490 builder, unknownTypeQName.getPrefix());
491 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
492 dependentModule, unknownTypeQName.getLocalName());
493 return copyTypedefBuilder(lookedUpBuilder, true);
496 private TypeConstraints findConstraints(
497 final TypeAwareBuilder nodeToResolve,
498 final TypeConstraints constraints,
499 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
500 final ModuleBuilder builder) {
501 // union type cannot be restricted
502 if (nodeToResolve instanceof UnionTypeBuilder) {
506 // if referenced type is UnknownType again, search recursively with
507 // current constraints
508 final TypeDefinition<?> referencedType = nodeToResolve.getType();
509 List<RangeConstraint> ranges = Collections.emptyList();
510 List<LengthConstraint> lengths = Collections.emptyList();
511 List<PatternConstraint> patterns = Collections.emptyList();
512 Integer fractionDigits = null;
513 if (referencedType == null) {
514 final TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
515 ranges = tdb.getRanges();
516 constraints.addRanges(ranges);
517 lengths = tdb.getLengths();
518 constraints.addLengths(lengths);
519 patterns = tdb.getPatterns();
520 constraints.addPatterns(patterns);
521 fractionDigits = tdb.getFractionDigits();
522 constraints.setFractionDigits(fractionDigits);
524 } else if (referencedType instanceof ExtendedType) {
525 final ExtendedType ext = (ExtendedType) referencedType;
526 ranges = ext.getRanges();
527 constraints.addRanges(ranges);
528 lengths = ext.getLengths();
529 constraints.addLengths(lengths);
530 patterns = ext.getPatterns();
531 constraints.addPatterns(patterns);
532 fractionDigits = ext.getFractionDigits();
533 constraints.setFractionDigits(fractionDigits);
534 return findConstraints(
535 findTypedefBuilder(ext.getQName(), modules, builder),
536 constraints, modules, builder);
537 } else if (referencedType instanceof UnknownType) {
538 final UnknownType unknown = (UnknownType) referencedType;
539 ranges = unknown.getRangeStatements();
540 constraints.addRanges(ranges);
541 lengths = unknown.getLengthStatements();
542 constraints.addLengths(lengths);
543 patterns = unknown.getPatterns();
544 constraints.addPatterns(patterns);
545 fractionDigits = unknown.getFractionDigits();
546 constraints.setFractionDigits(fractionDigits);
548 String unknownTypePrefix = unknown.getQName().getPrefix();
549 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
550 unknownTypePrefix = builder.getPrefix();
552 final ModuleBuilder dependentModule = findDependentModule(modules,
553 builder, unknown.getQName().getPrefix());
554 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
555 unknown.getQName(), modules, builder);
556 return findConstraints(utBuilder, constraints, modules,
559 // HANDLE BASE YANG TYPE
560 mergeConstraints(referencedType, constraints);
566 * Go through all typedef statements from given module and search for one
570 * typedef statements to search
572 * name of searched typedef
573 * @return typedef with name equals to given name
575 private TypeDefinitionBuilder findTypedefBuilderByName(
576 final ModuleBuilder dependentModule, final String name) {
577 TypeDefinitionBuilder result = null;
578 final Set<TypeDefinitionBuilder> typedefs = dependentModule
579 .getModuleTypedefs();
580 for (TypeDefinitionBuilder td : typedefs) {
581 if (td.getQName().getLocalName().equals(name)) {
586 if (result == null) {
587 throw new YangParseException("Target module '"
588 + dependentModule.getName()
589 + "' does not contain typedef '" + name + "'.");
595 * Pull restriction from referenced type and add them to given constraints
597 * @param referencedType
600 private void mergeConstraints(final TypeDefinition<?> referencedType,
601 final TypeConstraints constraints) {
603 if (referencedType instanceof DecimalTypeDefinition) {
604 constraints.addRanges(((DecimalTypeDefinition) referencedType)
605 .getRangeStatements());
607 .setFractionDigits(((DecimalTypeDefinition) referencedType)
608 .getFractionDigits());
609 } else if (referencedType instanceof IntegerTypeDefinition) {
610 constraints.addRanges(((IntegerTypeDefinition) referencedType)
611 .getRangeStatements());
612 } else if (referencedType instanceof StringTypeDefinition) {
613 constraints.addPatterns(((StringTypeDefinition) referencedType)
615 constraints.addLengths(((StringTypeDefinition) referencedType)
616 .getLengthStatements());
617 } else if (referencedType instanceof BinaryTypeDefinition) {
618 constraints.addLengths(((BinaryTypeDefinition) referencedType)
619 .getLengthConstraints());
624 * Go through all augmentation definitions and resolve them. This method
625 * also finds referenced node and add child nodes to it.
628 * all available modules
630 private void resolveAugments(
631 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
632 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
633 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
634 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
636 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
638 allModulesList.add(inner.getValue());
639 allModulesSet.add(inner.getValue());
643 for (int i = 0; i < allModulesList.size(); i++) {
644 final ModuleBuilder module = allModulesList.get(i);
645 // try to resolve augments in module
646 resolveAugment(modules, module);
647 // while all augments are not resolved
648 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
650 while (!(module.getAugmentsResolved() == module.getAddedAugments()
652 ModuleBuilder nextModule = null;
653 // try resolve other module augments
655 nextModule = allModulesIterator.next();
656 resolveAugment(modules, nextModule);
657 } catch (NoSuchElementException e) {
658 throw new YangParseException(
659 "Failed to resolve augments in module '"
660 + module.getName() + "'.", e);
662 // then try to resolve first module again
663 resolveAugment(modules, module);
671 * all available modules
675 private void resolveAugment(
676 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
677 final ModuleBuilder module) {
678 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
679 for (AugmentationSchemaBuilder augmentBuilder : module
680 .getAddedAugments()) {
681 final SchemaPath augmentTargetSchemaPath = augmentBuilder
683 final List<QName> path = augmentTargetSchemaPath.getPath();
686 final QName qname = path.get(i);
687 String prefix = qname.getPrefix();
688 if (prefix == null) {
689 prefix = module.getPrefix();
692 DataSchemaNodeBuilder currentParent = null;
693 final ModuleBuilder dependentModule = findDependentModule(
694 modules, module, prefix);
695 for (DataSchemaNodeBuilder child : dependentModule
697 final QName childQName = child.getQName();
698 if (childQName.getLocalName().equals(qname.getLocalName())) {
699 currentParent = child;
705 for (; i < path.size(); i++) {
706 final QName currentQName = path.get(i);
707 DataSchemaNodeBuilder newParent = null;
708 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
710 final QName childQName = child.getQName();
711 if (childQName.getLocalName().equals(
712 currentQName.getLocalName())) {
717 if (newParent == null) {
718 break; // node not found, quit search
720 currentParent = newParent;
724 final QName currentQName = currentParent.getQName();
725 final QName lastAugmentPathElement = path.get(path.size() - 1);
726 if (currentQName.getLocalName().equals(
727 lastAugmentPathElement.getLocalName())) {
728 ParserUtils.fillAugmentTarget(augmentBuilder,
729 (ChildNodeBuilder) currentParent);
730 ((AugmentationTargetBuilder) currentParent)
731 .addAugmentation(augmentBuilder);
732 module.augmentResolved();
739 * Go through identity statements defined in current module and resolve
740 * their 'base' statement if present.
745 * module being resolved
747 private void resolveIdentities(
748 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
749 final ModuleBuilder module) {
750 final Set<IdentitySchemaNodeBuilder> identities = module
751 .getAddedIdentities();
752 for (IdentitySchemaNodeBuilder identity : identities) {
753 final String baseIdentityName = identity.getBaseIdentityName();
754 if (baseIdentityName != null) {
755 String baseIdentityPrefix = null;
756 String baseIdentityLocalName = null;
757 if (baseIdentityName.contains(":")) {
758 final String[] splitted = baseIdentityName.split(":");
759 baseIdentityPrefix = splitted[0];
760 baseIdentityLocalName = splitted[1];
762 baseIdentityPrefix = module.getPrefix();
763 baseIdentityLocalName = baseIdentityName;
765 final ModuleBuilder dependentModule = findDependentModule(
766 modules, module, baseIdentityPrefix);
768 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
769 .getAddedIdentities();
770 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
771 if (idBuilder.getQName().getLocalName()
772 .equals(baseIdentityLocalName)) {
773 identity.setBaseIdentity(idBuilder);
781 * Go through uses statements defined in current module and resolve their
787 * module being resolved
789 private void resolveUses(
790 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
791 final ModuleBuilder module) {
792 final Map<List<String>, UsesNodeBuilder> moduleUses = module
793 .getAddedUsesNodes();
794 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
796 final List<String> key = entry.getKey();
797 final UsesNodeBuilder usesNode = entry.getValue();
799 final String groupingName = key.get(key.size() - 1);
801 for (RefineHolder refine : usesNode.getRefines()) {
803 final String defaultStr = refine.getDefaultStr();
804 final Boolean mandatory = refine.isMandatory();
805 final MustDefinition must = refine.getMust();
806 final Boolean presence = refine.isPresence();
807 final Integer min = refine.getMinElements();
808 final Integer max = refine.getMaxElements();
809 final List<UnknownSchemaNodeBuilder> unknownNodes = refine
812 Builder refineTarget = getRefineTargetBuilder(groupingName,
813 refine, modules, module);
814 if (refineTarget instanceof LeafSchemaNodeBuilder) {
815 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) refineTarget;
816 if (defaultStr != null && !("".equals(defaultStr))) {
817 leaf.setDefaultStr(defaultStr);
819 if (mandatory != null) {
820 leaf.getConstraints().setMandatory(mandatory);
823 leaf.getConstraints().addMustDefinition(must);
825 if (unknownNodes != null) {
826 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
827 leaf.addUnknownSchemaNode(unknown);
830 usesNode.addRefineNode(leaf);
831 } else if (refineTarget instanceof ContainerSchemaNodeBuilder) {
832 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) refineTarget;
833 if (presence != null) {
834 container.setPresence(presence);
837 container.getConstraints().addMustDefinition(must);
839 if (unknownNodes != null) {
840 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
841 container.addUnknownSchemaNode(unknown);
844 usesNode.addRefineNode(container);
845 } else if (refineTarget instanceof ListSchemaNodeBuilder) {
846 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) refineTarget;
848 list.getConstraints().addMustDefinition(must);
851 list.getConstraints().setMinElements(min);
854 list.getConstraints().setMaxElements(max);
856 if (unknownNodes != null) {
857 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
858 list.addUnknownSchemaNode(unknown);
861 } else if (refineTarget instanceof LeafListSchemaNodeBuilder) {
862 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
863 groupingName, refine, modules, module);
865 leafList.getConstraints().addMustDefinition(must);
868 leafList.getConstraints().setMinElements(min);
871 leafList.getConstraints().setMaxElements(max);
873 if (unknownNodes != null) {
874 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
875 leafList.addUnknownSchemaNode(unknown);
878 } else if (refineTarget instanceof ChoiceBuilder) {
879 final ChoiceBuilder choice = (ChoiceBuilder) refineTarget;
880 if (defaultStr != null) {
881 choice.setDefaultCase(defaultStr);
883 if (mandatory != null) {
884 choice.getConstraints().setMandatory(mandatory);
886 if (unknownNodes != null) {
887 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
888 choice.addUnknownSchemaNode(unknown);
891 } else if (refineTarget instanceof AnyXmlBuilder) {
892 final AnyXmlBuilder anyXml = (AnyXmlBuilder) refineTarget;
893 if (mandatory != null) {
894 anyXml.getConstraints().setMandatory(mandatory);
897 anyXml.getConstraints().addMustDefinition(must);
899 if (unknownNodes != null) {
900 for (UnknownSchemaNodeBuilder unknown : unknownNodes) {
901 anyXml.addUnknownSchemaNode(unknown);
910 * Find original builder of refine node and return copy of this builder.
912 * @param groupingPath
913 * path to grouping which contains node to refine
915 * refine object containing informations about refine
920 * @return copy of Builder object of node to be refined if it is present in
921 * grouping, null otherwise
923 private Builder getRefineTargetBuilder(final String groupingPath,
924 final RefineHolder refine,
925 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
926 final ModuleBuilder module) {
927 Builder result = null;
928 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
929 refine.getName(), modules, module);
930 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
932 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
933 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
935 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
936 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
938 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
939 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
941 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
942 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
944 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
945 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
947 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
949 throw new YangParseException("Target '" + refine.getName()
950 + "' can not be refined");
956 * Find builder of refine node.
958 * @param groupingPath
959 * path to grouping which contains node to refine
960 * @param refineNodeName
961 * name of node to be refined
966 * @return Builder object of refine node if it is present in grouping, null
969 private Builder findRefineTargetBuilder(final String groupingPath,
970 final String refineNodeName,
971 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
972 final ModuleBuilder module) {
973 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
974 final List<String> builderPath = new ArrayList<String>();
975 String prefix = null;
976 for (QName qname : path.getPath()) {
977 builderPath.add(qname.getLocalName());
978 prefix = qname.getPrefix();
980 if (prefix == null) {
981 prefix = module.getPrefix();
984 final ModuleBuilder dependentModule = findDependentModule(modules,
986 builderPath.add(0, "grouping");
987 builderPath.add(0, dependentModule.getName());
988 final GroupingBuilder builder = (GroupingBuilder) dependentModule
989 .getNode(builderPath);
991 return builder.getChildNode(refineNodeName);
994 private QName findFullQName(
995 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
996 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
998 String baseString = idref.getBaseString();
999 if (baseString.contains(":")) {
1000 String[] splittedBase = baseString.split(":");
1001 if (splittedBase.length > 2) {
1002 throw new YangParseException(
1003 "Failed to parse identityref base: " + baseString);
1005 String prefix = splittedBase[0];
1006 String name = splittedBase[1];
1007 ModuleBuilder dependentModule = findDependentModule(modules,
1009 result = new QName(dependentModule.getNamespace(),
1010 dependentModule.getRevision(), prefix, name);
1012 result = new QName(module.getNamespace(), module.getRevision(),
1013 module.getPrefix(), baseString);
1019 * Find dependent module based on given prefix
1022 * all available modules
1026 * target module prefix
1029 private ModuleBuilder findDependentModule(
1030 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1031 final ModuleBuilder module, final String prefix) {
1032 ModuleBuilder dependentModule = null;
1033 Date dependentModuleRevision = null;
1035 if (prefix.equals(module.getPrefix())) {
1036 dependentModule = module;
1038 final ModuleImport dependentModuleImport = ParserUtils
1039 .getModuleImport(module, prefix);
1040 if (dependentModuleImport == null) {
1041 throw new YangParseException("No import found with prefix '"
1042 + prefix + "' in module " + module.getName() + "'.");
1044 final String dependentModuleName = dependentModuleImport
1046 dependentModuleRevision = dependentModuleImport.getRevision();
1048 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1049 .get(dependentModuleName);
1050 if (moduleBuildersByRevision == null) {
1051 throw new YangParseException(
1052 "Failed to find dependent module '"
1053 + dependentModuleName + "' needed by module '"
1054 + module.getName() + "'.");
1056 if (dependentModuleRevision == null) {
1057 dependentModule = moduleBuildersByRevision.lastEntry()
1060 dependentModule = moduleBuildersByRevision
1061 .get(dependentModuleRevision);
1065 if (dependentModule == null) {
1066 throw new YangParseException(
1067 "Failed to find dependent module with prefix '" + prefix
1068 + "' and revision '" + dependentModuleRevision
1071 return dependentModule;
1074 private static class SchemaContextImpl implements SchemaContext {
1075 private final Set<Module> modules;
1077 private SchemaContextImpl(final Set<Module> modules) {
1078 this.modules = modules;
1082 public Set<DataSchemaNode> getDataDefinitions() {
1083 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
1084 for (Module m : modules) {
1085 dataDefs.addAll(m.getChildNodes());
1091 public Set<Module> getModules() {
1096 public Set<NotificationDefinition> getNotifications() {
1097 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
1098 for (Module m : modules) {
1099 notifications.addAll(m.getNotifications());
1101 return notifications;
1105 public Set<RpcDefinition> getOperations() {
1106 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
1107 for (Module m : modules) {
1108 rpcs.addAll(m.getRpcs());
1114 public Set<ExtensionDefinition> getExtensions() {
1115 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
1116 for (Module m : modules) {
1117 extensions.addAll(m.getExtensionSchemaNodes());
1123 public Module findModuleByName(final String name, final Date revision) {
1124 if ((name != null) && (revision != null)) {
1125 for (final Module module : modules) {
1126 if (module.getName().equals(name)
1127 && module.getRevision().equals(revision)) {
1136 public Module findModuleByNamespace(final URI namespace) {
1137 if (namespace != null) {
1138 for (final Module module : modules) {
1139 if (module.getNamespace().equals(namespace)) {