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.List;
24 import java.util.TreeMap;
26 import org.antlr.v4.runtime.ANTLRInputStream;
27 import org.antlr.v4.runtime.CommonTokenStream;
28 import org.antlr.v4.runtime.tree.ParseTree;
29 import org.antlr.v4.runtime.tree.ParseTreeWalker;
30 import org.opendaylight.controller.antlrv4.code.gen.YangLexer;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
32 import org.opendaylight.controller.yang.common.QName;
33 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
34 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
35 import org.opendaylight.controller.yang.model.api.Module;
36 import org.opendaylight.controller.yang.model.api.ModuleImport;
37 import org.opendaylight.controller.yang.model.api.MustDefinition;
38 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
39 import org.opendaylight.controller.yang.model.api.RpcDefinition;
40 import org.opendaylight.controller.yang.model.api.SchemaContext;
41 import org.opendaylight.controller.yang.model.api.SchemaPath;
42 import org.opendaylight.controller.yang.model.api.TypeDefinition;
43 import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
44 import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition;
45 import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
46 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
47 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
48 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
49 import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
50 import org.opendaylight.controller.yang.model.parser.api.YangModelParser;
51 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder;
52 import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder;
53 import org.opendaylight.controller.yang.model.parser.builder.api.Builder;
54 import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder;
55 import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder;
56 import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder;
57 import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder;
58 import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder;
59 import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder;
60 import org.opendaylight.controller.yang.model.parser.builder.impl.AnyXmlBuilder;
61 import org.opendaylight.controller.yang.model.parser.builder.impl.ChoiceBuilder;
62 import org.opendaylight.controller.yang.model.parser.builder.impl.ContainerSchemaNodeBuilder;
63 import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder;
64 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafListSchemaNodeBuilder;
65 import org.opendaylight.controller.yang.model.parser.builder.impl.LeafSchemaNodeBuilder;
66 import org.opendaylight.controller.yang.model.parser.builder.impl.ListSchemaNodeBuilder;
67 import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder;
68 import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder;
69 import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder;
70 import org.opendaylight.controller.yang.model.parser.util.ParserUtils;
71 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
72 import org.opendaylight.controller.yang.model.parser.util.RefineHolder.Refine;
73 import org.opendaylight.controller.yang.model.parser.util.TypeConstraints;
74 import org.opendaylight.controller.yang.model.parser.util.YangParseException;
75 import org.opendaylight.controller.yang.model.util.ExtendedType;
76 import org.opendaylight.controller.yang.model.util.UnknownType;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 public class YangModelParserImpl implements YangModelParser {
82 private static final Logger logger = LoggerFactory
83 .getLogger(YangModelParserImpl.class);
86 public Module parseYangModel(final String yangFile) {
87 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFile);
88 final Set<Module> result = build(modules);
89 return result.iterator().next();
93 public Set<Module> parseYangModels(final String... yangFiles) {
94 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFiles);
95 return build(modules);
99 public Set<Module> parseYangModelsFromStreams(
100 final InputStream... yangModelStreams) {
101 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
102 return build(modules);
106 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
107 return new SchemaContextImpl(modules);
110 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
111 final String... yangFiles) {
112 final InputStream[] streams = loadStreams(yangFiles);
113 Map<String, TreeMap<Date, ModuleBuilder>> result = Collections
116 if (streams != null) {
117 result = resolveModuleBuilders(streams);
118 closeStreams(streams);
123 private InputStream[] loadStreams(final String... yangFiles) {
124 final InputStream[] streams = new InputStream[yangFiles.length];
125 for (int i = 0; i < yangFiles.length; i++) {
126 final String yangFileName = yangFiles[i];
127 final File yangFile = new File(yangFileName);
129 streams[i] = new FileInputStream(yangFile);
130 } catch (FileNotFoundException e) {
131 logger.warn("Exception while reading yang stream: "
138 private void closeStreams(final InputStream[] streams) {
139 if (streams != null) {
140 for (int i = 0; i < streams.length; i++) {
142 if (streams[i] != null) {
145 } catch (IOException e) {
146 logger.warn("Exception while closing yang stream: "
153 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
154 final InputStream... yangFiles) {
155 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
156 final ParseTreeWalker walker = new ParseTreeWalker();
157 final List<ParseTree> trees = parseStreams(yangFiles);
158 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
161 // if validation fails with any file, do not continue and throw
\r
163 for (int i = 0; i < trees.size(); i++) {
\r
165 final YangModelValidationListener yangModelParser = new YangModelValidationListener();
\r
166 walker.walk(yangModelParser, trees.get(i));
\r
167 } catch (IllegalStateException e) {
\r
168 // wrap exception to add information about which file failed
\r
169 throw new YangValidationException(
\r
170 "Yang validation failed for file" + yangFiles[i], e);
\r
175 YangModelParserListenerImpl yangModelParser = null;
176 for (int i = 0; i < trees.size(); i++) {
177 yangModelParser = new YangModelParserListenerImpl();
178 walker.walk(yangModelParser, trees.get(i));
179 builders[i] = yangModelParser.getModuleBuilder();
182 for (ModuleBuilder builder : builders) {
183 final String builderName = builder.getName();
184 Date builderRevision = builder.getRevision();
185 if (builderRevision == null) {
186 builderRevision = new Date(0L);
188 TreeMap<Date, ModuleBuilder> builderByRevision = modules
190 if (builderByRevision == null) {
191 builderByRevision = new TreeMap<Date, ModuleBuilder>();
193 builderByRevision.put(builderRevision, builder);
194 modules.put(builderName, builderByRevision);
199 private List<ParseTree> parseStreams(final InputStream... yangStreams) {
200 final List<ParseTree> trees = new ArrayList<ParseTree>();
201 for (InputStream yangStream : yangStreams) {
202 trees.add(parseStream(yangStream));
207 private ParseTree parseStream(final InputStream yangStream) {
208 ParseTree result = null;
210 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
211 final YangLexer lexer = new YangLexer(input);
212 final CommonTokenStream tokens = new CommonTokenStream(lexer);
213 final YangParser parser = new YangParser(tokens);
214 result = parser.yang();
215 } catch (IOException e) {
216 logger.warn("Exception while reading yang file: " + yangStream, e);
221 private Set<Module> build(final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
223 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
225 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
227 final ModuleBuilder moduleBuilder = childEntry.getValue();
228 validateModule(modules, moduleBuilder);
233 final Set<Module> result = new HashSet<Module>();
234 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
236 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
237 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
239 final ModuleBuilder moduleBuilder = childEntry.getValue();
240 final Module module = moduleBuilder.build();
241 modulesByRevision.put(childEntry.getKey(), module);
248 private void validateModule(
249 Map<String, TreeMap<Date, ModuleBuilder>> modules,
250 ModuleBuilder builder) {
251 resolveDirtyNodes(modules, builder);
252 resolveAugments(modules, builder);
253 resolveIdentities(modules, builder);
254 resolveUses(modules, builder);
258 * Search for dirty nodes (node which contains UnknownType) and resolve
262 * all available modules
266 private void resolveDirtyNodes(
267 Map<String, TreeMap<Date, ModuleBuilder>> modules,
268 ModuleBuilder module) {
269 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
271 if (!dirtyNodes.isEmpty()) {
272 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
275 final TypeAwareBuilder nodeToResolve = entry.getValue();
276 // different handling for union types
277 if (nodeToResolve instanceof UnionTypeBuilder) {
278 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
279 List<TypeDefinition<?>> unionTypes = union.getTypes();
280 List<UnknownType> toRemove = new ArrayList<UnknownType>();
281 for (TypeDefinition<?> td : unionTypes) {
282 if (td instanceof UnknownType) {
283 UnknownType unknownType = (UnknownType) td;
284 TypeDefinitionBuilder resolvedType = resolveTypeUnion(
285 nodeToResolve, unknownType, modules, module);
286 union.setType(resolvedType);
287 toRemove.add(unknownType);
290 unionTypes.removeAll(toRemove);
292 TypeDefinitionBuilder resolvedType = resolveType(
293 nodeToResolve, modules, module);
294 nodeToResolve.setType(resolvedType);
300 private TypeDefinitionBuilder resolveType(TypeAwareBuilder typeToResolve,
301 Map<String, TreeMap<Date, ModuleBuilder>> modules,
302 ModuleBuilder builder) {
303 TypeConstraints constraints = new TypeConstraints();
305 TypeDefinitionBuilder targetType = getTypedefBuilder(typeToResolve,
307 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 TypeAwareBuilder typeToResolve, UnknownType unknownType,
319 Map<String, TreeMap<Date, ModuleBuilder>> modules,
320 ModuleBuilder builder) {
321 TypeConstraints constraints = new TypeConstraints();
323 TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
324 unknownType, modules, builder);
325 TypeConstraints tConstraints = findConstraints(typeToResolve,
326 constraints, modules, builder);
327 targetType.setRanges(tConstraints.getRange());
328 targetType.setLengths(tConstraints.getLength());
329 targetType.setPatterns(tConstraints.getPatterns());
330 targetType.setFractionDigits(tConstraints.getFractionDigits());
335 private TypeDefinitionBuilder getTypedefBuilder(
336 TypeAwareBuilder nodeToResolve,
337 Map<String, TreeMap<Date, ModuleBuilder>> modules,
338 ModuleBuilder builder) {
340 TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
341 if (nodeToResolveBase != null
342 && !(nodeToResolveBase instanceof UnknownType)) {
343 return (TypeDefinitionBuilder) nodeToResolve;
346 UnknownType unknownType = (UnknownType) nodeToResolve.getType();
348 QName unknownTypeQName = unknownType.getQName();
349 String unknownTypeName = unknownTypeQName.getLocalName();
350 String unknownTypePrefix = unknownTypeQName.getPrefix();
352 // search for module which contains referenced typedef
353 ModuleBuilder dependentModule = findDependentModule(modules, builder,
355 TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
356 dependentModule, unknownTypeName);
358 TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
359 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
360 TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
361 lookedUpBuilderCopy, modules, dependentModule);
365 private TypeDefinitionBuilder getUnionBuilder(
366 TypeAwareBuilder nodeToResolve, UnknownType unknownType,
367 Map<String, TreeMap<Date, ModuleBuilder>> modules,
368 ModuleBuilder module) {
370 TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
371 if (baseTypeToResolve != null
372 && !(baseTypeToResolve instanceof UnknownType)) {
373 return (TypeDefinitionBuilder) nodeToResolve;
376 QName unknownTypeQName = unknownType.getQName();
377 String unknownTypeName = unknownTypeQName.getLocalName();
378 String unknownTypePrefix = unknownTypeQName.getPrefix();
380 // search for module which contains referenced typedef
381 ModuleBuilder dependentModule = findDependentModule(modules, module,
383 TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
384 dependentModule, unknownTypeName);
386 TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
387 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
388 TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
389 lookedUpBuilderCopy, modules, dependentModule);
393 private TypeDefinitionBuilder copyTypedefBuilder(TypeDefinitionBuilder old,
394 boolean seekByTypedefBuilder) {
395 if (old instanceof UnionTypeBuilder) {
396 UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
397 UnionTypeBuilder newUnion = new UnionTypeBuilder();
398 for (TypeDefinition<?> td : oldUnion.getTypes()) {
399 newUnion.setType(td);
401 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
402 newUnion.setType(copyTypedefBuilder(tdb, true));
407 QName oldName = old.getQName();
408 QName newName = new QName(oldName.getNamespace(),
409 oldName.getRevision(), oldName.getPrefix(),
410 oldName.getLocalName());
411 TypeDefinitionBuilder tdb = new TypedefBuilder(newName);
413 tdb.setRanges(old.getRanges());
414 tdb.setLengths(old.getLengths());
415 tdb.setPatterns(old.getPatterns());
416 tdb.setFractionDigits(old.getFractionDigits());
418 TypeDefinition<?> oldType = old.getType();
419 if (oldType == null) {
420 tdb.setType(old.getTypedef());
422 tdb.setType(oldType);
425 if (!seekByTypedefBuilder) {
426 tdb.setDescription(old.getDescription());
427 tdb.setReference(old.getReference());
428 tdb.setStatus(old.getStatus());
429 tdb.setDefaultValue(old.getDefaultValue());
430 tdb.setUnits(old.getUnits());
435 private TypeDefinitionBuilder resolveCopiedBuilder(
436 TypeDefinitionBuilder copy,
437 Map<String, TreeMap<Date, ModuleBuilder>> modules,
438 ModuleBuilder builder) {
440 if (copy instanceof UnionTypeBuilder) {
441 UnionTypeBuilder union = (UnionTypeBuilder) copy;
442 List<TypeDefinition<?>> unionTypes = union.getTypes();
443 List<UnknownType> toRemove = new ArrayList<UnknownType>();
444 for (TypeDefinition<?> td : unionTypes) {
445 if (td instanceof UnknownType) {
446 UnknownType unknownType = (UnknownType) td;
447 TypeDefinitionBuilder resolvedType = resolveTypeUnion(
448 union, unknownType, modules, builder);
449 union.setType(resolvedType);
450 toRemove.add(unknownType);
453 unionTypes.removeAll(toRemove);
458 TypeDefinition<?> base = copy.getType();
459 TypeDefinitionBuilder baseTdb = copy.getTypedef();
460 if (base != null && !(base instanceof UnknownType)) {
462 } else if (base instanceof UnknownType) {
463 UnknownType unknownType = (UnknownType) base;
464 QName unknownTypeQName = unknownType.getQName();
465 String unknownTypePrefix = unknownTypeQName.getPrefix();
466 ModuleBuilder dependentModule = findDependentModule(modules,
467 builder, unknownTypePrefix);
468 TypeDefinitionBuilder unknownTypeBuilder = getTypedefBuilder(copy,
469 modules, dependentModule);
470 copy.setType(unknownTypeBuilder);
472 } else if (base == null && baseTdb != null) {
473 // make a copy of baseTypeDef and call again
474 TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(baseTdb,
476 TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
477 baseTdbCopy, modules, builder);
478 copy.setType(baseTdbCopyResolved);
481 throw new IllegalStateException(
482 "TypeDefinitionBuilder in unexpected state");
486 private TypeDefinitionBuilder findTypedefBuilder(QName unknownTypeQName,
487 Map<String, TreeMap<Date, ModuleBuilder>> modules,
488 ModuleBuilder builder) {
490 String unknownTypeName = unknownTypeQName.getLocalName();
491 String unknownTypePrefix = unknownTypeQName.getPrefix();
493 // search for module which contains referenced typedef
494 ModuleBuilder dependentModule = findDependentModule(modules, builder,
497 TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
498 dependentModule, unknownTypeName);
500 TypeDefinitionBuilder copied = copyTypedefBuilder(lookedUpBuilder, true);
504 private TypeConstraints findConstraints(TypeAwareBuilder nodeToResolve,
505 TypeConstraints constraints,
506 Map<String, TreeMap<Date, ModuleBuilder>> modules,
507 ModuleBuilder builder) {
509 // union type cannot be restricted
510 if (nodeToResolve instanceof UnionTypeBuilder) {
514 // if referenced type is UnknownType again, search recursively with
515 // current constraints
516 TypeDefinition<?> referencedType = nodeToResolve.getType();
517 List<RangeConstraint> ranges = Collections.emptyList();
518 List<LengthConstraint> lengths = Collections.emptyList();
519 List<PatternConstraint> patterns = Collections.emptyList();
520 Integer fractionDigits = null;
521 if (referencedType == null) {
522 TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
523 ranges = tdb.getRanges();
524 constraints.addRanges(ranges);
525 lengths = tdb.getLengths();
526 constraints.addLengths(lengths);
527 patterns = tdb.getPatterns();
528 constraints.addPatterns(patterns);
529 fractionDigits = tdb.getFractionDigits();
530 constraints.setFractionDigits(fractionDigits);
532 } else if (referencedType instanceof ExtendedType) {
533 ExtendedType ext = (ExtendedType) referencedType;
534 ranges = ext.getRanges();
535 constraints.addRanges(ranges);
536 lengths = ext.getLengths();
537 constraints.addLengths(lengths);
538 patterns = ext.getPatterns();
539 constraints.addPatterns(patterns);
540 fractionDigits = ext.getFractionDigits();
541 constraints.setFractionDigits(fractionDigits);
542 return findConstraints(
543 findTypedefBuilder(ext.getQName(), modules, builder),
544 constraints, modules, builder);
545 } else if (referencedType instanceof UnknownType) {
546 UnknownType unknown = (UnknownType) referencedType;
548 ranges = unknown.getRangeStatements();
549 constraints.addRanges(ranges);
550 lengths = unknown.getLengthStatements();
551 constraints.addLengths(lengths);
552 patterns = unknown.getPatterns();
553 constraints.addPatterns(patterns);
554 fractionDigits = unknown.getFractionDigits();
555 constraints.setFractionDigits(fractionDigits);
557 String unknownTypePrefix = unknown.getQName().getPrefix();
558 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
559 unknownTypePrefix = builder.getPrefix();
561 ModuleBuilder dependentModule = findDependentModule(modules,
562 builder, unknown.getQName().getPrefix());
563 TypeDefinitionBuilder unknownTypeBuilder = findTypedefBuilder(
564 unknown.getQName(), modules, builder);
565 return findConstraints(unknownTypeBuilder, constraints, modules,
568 // HANDLE BASE YANG TYPE
569 mergeConstraints(referencedType, constraints);
576 * Go through all typedef statements from given module and search for one
580 * typedef statements to search
582 * name of searched typedef
583 * @return typedef with name equals to given name
585 private TypeDefinitionBuilder findTypedefBuilderByName(
586 ModuleBuilder dependentModule, String name) {
587 TypeDefinitionBuilder result = null;
588 final Set<TypeDefinitionBuilder> typedefs = dependentModule
589 .getModuleTypedefs();
590 for (TypeDefinitionBuilder td : typedefs) {
591 if (td.getQName().getLocalName().equals(name)) {
596 if (result == null) {
597 throw new YangParseException("Target module '"
598 + dependentModule.getName()
599 + "' does not contain typedef '" + name + "'.");
605 * Pull restriction from referenced type and add them to given constraints
607 * @param referencedType
610 private void mergeConstraints(TypeDefinition<?> referencedType,
611 TypeConstraints constraints) {
613 if (referencedType instanceof DecimalTypeDefinition) {
614 constraints.addRanges(((DecimalTypeDefinition) referencedType)
615 .getRangeStatements());
617 .setFractionDigits(((DecimalTypeDefinition) referencedType)
618 .getFractionDigits());
619 } else if (referencedType instanceof IntegerTypeDefinition) {
620 constraints.addRanges(((IntegerTypeDefinition) referencedType)
621 .getRangeStatements());
622 } else if (referencedType instanceof StringTypeDefinition) {
623 constraints.addPatterns(((StringTypeDefinition) referencedType)
625 constraints.addLengths(((StringTypeDefinition) referencedType)
626 .getLengthStatements());
627 } else if (referencedType instanceof BinaryTypeDefinition) {
628 constraints.addLengths(((BinaryTypeDefinition) referencedType)
629 .getLengthConstraints());
634 * Go through all augmentation definitions and resolve them. This means find
635 * referenced node and add child nodes to it.
638 * all available modules
642 public void resolveAugments(
643 Map<String, TreeMap<Date, ModuleBuilder>> modules,
644 ModuleBuilder module) {
645 Set<AugmentationSchemaBuilder> augmentBuilders = module
648 for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) {
649 SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath();
650 List<QName> path = augmentTargetSchemaPath.getPath();
652 String prefix = path.get(path.size() - 1).getPrefix();
653 List<String> augmentTargetPath = new ArrayList<String>();
655 for (QName pathPart : path) {
656 if (pathPart.getPrefix().equals(prefix)) {
657 augmentTargetPath.add(pathPart.getLocalName());
660 if (prefix == null) {
661 prefix = module.getPrefix();
664 ModuleBuilder dependentModule = findDependentModule(modules,
666 augmentTargetPath.add(0, dependentModule.getName());
668 AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule
669 .getNode(augmentTargetPath);
671 // augment target could be another augment, so if target is not
672 // found, get augments in target module and search for target node
673 if (augmentTarget == null) {
674 for (AugmentationSchemaBuilder builder : dependentModule
675 .getAddedAugments()) {
676 for (DataSchemaNodeBuilder dataBuilder : builder
678 SchemaPath dataBuilderPath = dataBuilder.getPath();
679 List<QName> qnamePath = dataBuilderPath.getPath();
680 List<String> dataBuilderStringPath = new ArrayList<String>();
682 // start from 1: augment name omitted
683 for (int i = 1; i < qnamePath.size(); i++) {
684 dataBuilderStringPath.add(qnamePath.get(i)
687 // module name omitted
688 augmentTargetPath.remove(0);
689 if (augmentTargetPath.equals(dataBuilderStringPath)) {
690 augmentTarget = (AugmentationTargetBuilder) dataBuilder;
691 augmentTarget.addAugmentation(augmentBuilder);
692 fillAugmentTarget(augmentBuilder,
693 (ChildNodeBuilder) augmentTarget);
698 augmentTarget.addAugmentation(augmentBuilder);
699 fillAugmentTarget(augmentBuilder,
700 (ChildNodeBuilder) augmentTarget);
706 * Add all augment's child nodes to given target.
711 private void fillAugmentTarget(AugmentationSchemaBuilder augment,
712 ChildNodeBuilder target) {
713 for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
714 builder.setAugmenting(true);
715 target.addChildNode(builder);
720 * Go through identity statements defined in current module and resolve
721 * their 'base' statement if present.
726 * module being resolved
728 private void resolveIdentities(
729 Map<String, TreeMap<Date, ModuleBuilder>> modules,
730 ModuleBuilder module) {
731 Set<IdentitySchemaNodeBuilder> identities = module.getAddedIdentities();
732 for (IdentitySchemaNodeBuilder identity : identities) {
733 String baseIdentityName = identity.getBaseIdentityName();
734 if (baseIdentityName != null) {
735 String baseIdentityPrefix = null;
736 String baseIdentityLocalName = null;
737 if (baseIdentityName.contains(":")) {
738 String[] splitted = baseIdentityName.split(":");
739 baseIdentityPrefix = splitted[0];
740 baseIdentityLocalName = splitted[1];
742 baseIdentityPrefix = module.getPrefix();
743 baseIdentityLocalName = baseIdentityName;
745 ModuleBuilder dependentModule = findDependentModule(modules,
746 module, baseIdentityPrefix);
748 Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
749 .getAddedIdentities();
750 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
751 if (idBuilder.getQName().getLocalName()
752 .equals(baseIdentityLocalName)) {
753 identity.setBaseIdentity(idBuilder);
761 * Go through uses statements defined in current module and resolve their
767 * module being resolved
769 private void resolveUses(Map<String, TreeMap<Date, ModuleBuilder>> modules,
770 ModuleBuilder module) {
771 Map<List<String>, UsesNodeBuilder> moduleUses = module
772 .getAddedUsesNodes();
773 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
775 List<String> key = entry.getKey();
776 UsesNodeBuilder usesNode = entry.getValue();
778 String groupingName = key.get(key.size() - 1);
780 List<RefineHolder> refines = usesNode.getRefines();
781 for (RefineHolder refine : refines) {
782 Refine refineType = refine.getType();
785 String defaultStr = refine.getDefaultStr();
786 Boolean mandatory = refine.isMandatory();
787 MustDefinition must = refine.getMust();
788 Boolean presence = refine.isPresence();
789 Integer min = refine.getMinElements();
790 Integer max = refine.getMaxElements();
792 switch (refineType) {
794 LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) getRefineTargetBuilder(
795 groupingName, refine, modules, module);
796 if (defaultStr != null && !("".equals(defaultStr))) {
797 leaf.setDefaultStr(defaultStr);
799 if (mandatory != null) {
800 leaf.getConstraints().setMandatory(mandatory);
803 leaf.getConstraints().addMustDefinition(must);
805 usesNode.addRefineNode(leaf);
808 ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) getRefineTargetBuilder(
809 groupingName, refine, modules, module);
810 if (presence != null) {
811 container.setPresence(presence);
814 container.getConstraints().addMustDefinition(must);
816 usesNode.addRefineNode(container);
819 ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) getRefineTargetBuilder(
820 groupingName, refine, modules, module);
822 list.getConstraints().addMustDefinition(must);
825 list.getConstraints().setMinElements(min);
828 list.getConstraints().setMaxElements(max);
832 LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
833 groupingName, refine, modules, module);
835 leafList.getConstraints().addMustDefinition(must);
838 leafList.getConstraints().setMinElements(min);
841 leafList.getConstraints().setMaxElements(max);
845 ChoiceBuilder choice = (ChoiceBuilder) getRefineTargetBuilder(
846 groupingName, refine, modules, module);
847 if (defaultStr != null) {
848 choice.setDefaultCase(defaultStr);
850 if (mandatory != null) {
851 choice.getConstraints().setMandatory(mandatory);
855 AnyXmlBuilder anyXml = (AnyXmlBuilder) getRefineTargetBuilder(
856 groupingName, refine, modules, module);
857 if (mandatory != null) {
858 anyXml.getConstraints().setMandatory(mandatory);
861 anyXml.getConstraints().addMustDefinition(must);
870 * Find original builder of refine node and return copy of this builder.
872 * @param groupingPath
873 * path to grouping which contains node to refine
875 * refine object containing informations about refine
880 * @return copy of Builder object of node to be refined if it is present in
881 * grouping, null otherwise
883 private Builder getRefineTargetBuilder(String groupingPath,
885 Map<String, TreeMap<Date, ModuleBuilder>> modules,
886 ModuleBuilder module) {
887 Builder result = null;
888 Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
889 refine.getName(), modules, module);
890 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
892 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
893 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
895 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
896 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
898 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
899 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
901 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
902 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
904 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
905 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
907 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
909 throw new YangParseException("Target '" + refine.getName()
910 + "' can not be refined");
916 * Find builder of refine node.
918 * @param groupingPath
919 * path to grouping which contains node to refine
920 * @param refineNodeName
921 * name of node to be refined
926 * @return Builder object of refine node if it is present in grouping, null
929 private Builder findRefineTargetBuilder(String groupingPath,
930 String refineNodeName,
931 Map<String, TreeMap<Date, ModuleBuilder>> modules,
932 ModuleBuilder module) {
933 SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
934 List<String> builderPath = new ArrayList<String>();
935 String prefix = null;
936 for (QName qname : path.getPath()) {
937 builderPath.add(qname.getLocalName());
938 prefix = qname.getPrefix();
940 if (prefix == null) {
941 prefix = module.getPrefix();
944 ModuleBuilder dependentModule = findDependentModule(modules, module,
946 builderPath.add(0, "grouping");
947 builderPath.add(0, dependentModule.getName());
948 GroupingBuilder builder = (GroupingBuilder) dependentModule
949 .getNode(builderPath);
951 return builder.getChildNode(refineNodeName);
955 * Find dependent module based on given prefix
958 * all available modules
962 * target module prefix
965 private ModuleBuilder findDependentModule(
966 Map<String, TreeMap<Date, ModuleBuilder>> modules,
967 ModuleBuilder module, String prefix) {
968 ModuleBuilder dependentModule = null;
969 Date dependentModuleRevision = null;
971 if (prefix.equals(module.getPrefix())) {
972 dependentModule = module;
974 ModuleImport dependentModuleImport = getModuleImport(module, prefix);
975 if (dependentModuleImport == null) {
976 throw new YangParseException("No import found with prefix '"
977 + prefix + "' in module " + module.getName() + "'.");
979 String dependentModuleName = dependentModuleImport.getModuleName();
980 dependentModuleRevision = dependentModuleImport.getRevision();
982 TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
983 .get(dependentModuleName);
984 if (moduleBuildersByRevision == null) {
985 throw new YangParseException(
986 "Failed to find dependent module '"
987 + dependentModuleName + "' needed by module '"
988 + module.getName() + "'.");
990 if (dependentModuleRevision == null) {
991 dependentModule = moduleBuildersByRevision.lastEntry()
994 dependentModule = moduleBuildersByRevision
995 .get(dependentModuleRevision);
999 if (dependentModule == null) {
1000 throw new YangParseException(
1001 "Failed to find dependent module with prefix '" + prefix
1002 + "' and revision '" + dependentModuleRevision
1005 return dependentModule;
1009 * Get module import referenced by given prefix.
1014 * prefix associated with import
1015 * @return ModuleImport based on given prefix
1017 private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) {
1018 ModuleImport moduleImport = null;
1019 for (ModuleImport mi : builder.getModuleImports()) {
1020 if (mi.getPrefix().equals(prefix)) {
1025 return moduleImport;
1028 private static class SchemaContextImpl implements SchemaContext {
1029 private final Set<Module> modules;
1031 private SchemaContextImpl(Set<Module> modules) {
1032 this.modules = modules;
1036 public Set<DataSchemaNode> getDataDefinitions() {
1037 final Set<DataSchemaNode> dataDefs = new HashSet<DataSchemaNode>();
1038 for (Module m : modules) {
1039 dataDefs.addAll(m.getChildNodes());
1045 public Set<Module> getModules() {
1050 public Set<NotificationDefinition> getNotifications() {
1051 final Set<NotificationDefinition> notifications = new HashSet<NotificationDefinition>();
1052 for (Module m : modules) {
1053 notifications.addAll(m.getNotifications());
1055 return notifications;
1059 public Set<RpcDefinition> getOperations() {
1060 final Set<RpcDefinition> rpcs = new HashSet<RpcDefinition>();
1061 for (Module m : modules) {
1062 rpcs.addAll(m.getRpcs());
1068 public Set<ExtensionDefinition> getExtensions() {
1069 final Set<ExtensionDefinition> extensions = new HashSet<ExtensionDefinition>();
1070 for (Module m : modules) {
1071 extensions.addAll(m.getExtensionSchemaNodes());
1077 public Module findModuleByName(final String name, final Date revision) {
1078 if ((name != null) && (revision != null)) {
1079 for (final Module module : modules) {
1080 if (module.getName().equals(name)
1081 && module.getRevision().equals(revision)) {
1090 public Module findModuleByNamespace(URI namespace) {
1091 if (namespace != null) {
1092 for (final Module module : modules) {
1093 if (module.getNamespace().equals(namespace)) {