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.util.ParserUtils;
74 import org.opendaylight.controller.yang.model.parser.util.RefineHolder;
75 import org.opendaylight.controller.yang.model.parser.util.RefineHolder.Refine;
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.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
84 public class YangModelParserImpl implements YangModelParser {
86 private static final Logger logger = LoggerFactory
87 .getLogger(YangModelParserImpl.class);
90 public Module parseYangModel(final String yangFile) {
91 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFile);
92 final Set<Module> result = build(modules);
93 return result.iterator().next();
97 public Set<Module> parseYangModels(final String... yangFiles) {
98 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangFiles);
99 return build(modules);
103 public Set<Module> parseYangModelsFromStreams(
104 final InputStream... yangModelStreams) {
105 final Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModuleBuilders(yangModelStreams);
106 return build(modules);
110 public SchemaContext resolveSchemaContext(final Set<Module> modules) {
111 return new SchemaContextImpl(modules);
114 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
115 final String... yangFiles) {
116 final InputStream[] streams = loadStreams(yangFiles);
117 Map<String, TreeMap<Date, ModuleBuilder>> result = Collections
120 if (streams != null) {
121 result = resolveModuleBuilders(streams);
122 closeStreams(streams);
127 private InputStream[] loadStreams(final String... yangFiles) {
128 final InputStream[] streams = new InputStream[yangFiles.length];
129 for (int i = 0; i < yangFiles.length; i++) {
130 final String yangFileName = yangFiles[i];
131 final File yangFile = new File(yangFileName);
133 streams[i] = new FileInputStream(yangFile);
134 } catch (FileNotFoundException e) {
135 logger.warn("Exception while reading yang stream: "
142 private void closeStreams(final InputStream[] streams) {
143 if (streams != null) {
144 for (int i = 0; i < streams.length; i++) {
146 if (streams[i] != null) {
149 } catch (IOException e) {
150 logger.warn("Exception while closing yang stream: "
157 private Map<String, TreeMap<Date, ModuleBuilder>> resolveModuleBuilders(
158 final InputStream... yangFiles) {
159 final Map<String, TreeMap<Date, ModuleBuilder>> modules = new HashMap<String, TreeMap<Date, ModuleBuilder>>();
160 final ParseTreeWalker walker = new ParseTreeWalker();
161 final List<ParseTree> trees = parseStreams(yangFiles);
162 final ModuleBuilder[] builders = new ModuleBuilder[trees.size()];
165 // if validation fails with any file, do not continue and throw
167 for (int i = 0; i < trees.size(); i++) {
169 final YangModelValidationListener yangModelParser = new YangModelValidationListener();
170 walker.walk(yangModelParser, trees.get(i));
171 } catch (IllegalStateException e) {
172 // wrap exception to add information about which file failed
173 throw new YangValidationException(
174 "Yang validation failed for file" + yangFiles[i], e);
178 YangModelParserListenerImpl yangModelParser = null;
179 for (int i = 0; i < trees.size(); i++) {
180 yangModelParser = new YangModelParserListenerImpl();
181 walker.walk(yangModelParser, trees.get(i));
182 builders[i] = yangModelParser.getModuleBuilder();
185 for (ModuleBuilder builder : builders) {
186 final String builderName = builder.getName();
187 Date builderRevision = builder.getRevision();
188 if (builderRevision == null) {
189 builderRevision = new Date(0L);
191 TreeMap<Date, ModuleBuilder> builderByRevision = modules
193 if (builderByRevision == null) {
194 builderByRevision = new TreeMap<Date, ModuleBuilder>();
196 builderByRevision.put(builderRevision, builder);
197 modules.put(builderName, builderByRevision);
202 private List<ParseTree> parseStreams(final InputStream... yangStreams) {
203 final List<ParseTree> trees = new ArrayList<ParseTree>();
204 for (InputStream yangStream : yangStreams) {
205 trees.add(parseStream(yangStream));
210 private ParseTree parseStream(final InputStream yangStream) {
211 ParseTree result = null;
213 final ANTLRInputStream input = new ANTLRInputStream(yangStream);
214 final YangLexer lexer = new YangLexer(input);
215 final CommonTokenStream tokens = new CommonTokenStream(lexer);
216 final YangParser parser = new YangParser(tokens);
217 result = parser.yang();
218 } catch (IOException e) {
219 logger.warn("Exception while reading yang file: " + yangStream, e);
224 private Set<Module> build(
225 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
226 // fix unresolved nodes
227 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
229 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
231 final ModuleBuilder moduleBuilder = childEntry.getValue();
232 fixUnresolvedNodes(modules, moduleBuilder);
235 resolveAugments(modules);
238 final Set<Module> result = new HashSet<Module>();
239 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
241 final Map<Date, Module> modulesByRevision = new HashMap<Date, Module>();
242 for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue()
244 final ModuleBuilder moduleBuilder = childEntry.getValue();
245 final Module module = moduleBuilder.build();
246 modulesByRevision.put(childEntry.getKey(), module);
253 private void fixUnresolvedNodes(
254 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
255 final ModuleBuilder builder) {
256 resolveDirtyNodes(modules, builder);
257 resolveIdentities(modules, builder);
258 resolveUses(modules, builder);
262 * Search for dirty nodes (node which contains UnknownType) and resolve
266 * all available modules
270 private void resolveDirtyNodes(
271 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
272 final ModuleBuilder module) {
273 final Map<List<String>, TypeAwareBuilder> dirtyNodes = module
275 if (!dirtyNodes.isEmpty()) {
276 for (Map.Entry<List<String>, TypeAwareBuilder> entry : dirtyNodes
279 final TypeAwareBuilder nodeToResolve = entry.getValue();
280 // different handling for union types
281 if (nodeToResolve instanceof UnionTypeBuilder) {
282 final UnionTypeBuilder union = (UnionTypeBuilder) nodeToResolve;
283 final List<TypeDefinition<?>> unionTypes = union.getTypes();
284 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
285 for (TypeDefinition<?> td : unionTypes) {
286 if (td instanceof UnknownType) {
287 final UnknownType unknownType = (UnknownType) td;
288 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
289 nodeToResolve, unknownType, modules, module);
290 union.setType(resolvedType);
291 toRemove.add(unknownType);
294 unionTypes.removeAll(toRemove);
295 } else if(nodeToResolve.getTypedef() instanceof IdentityrefTypeBuilder) {
296 IdentityrefTypeBuilder idref = (IdentityrefTypeBuilder)nodeToResolve.getTypedef();
297 nodeToResolve.setType(new IdentityrefType(findFullQName(modules, module, idref)));
299 final TypeDefinitionBuilder resolvedType = resolveType(
300 nodeToResolve, modules, module);
301 nodeToResolve.setType(resolvedType);
307 private TypeDefinitionBuilder resolveType(
308 final TypeAwareBuilder typeToResolve,
309 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
310 final ModuleBuilder builder) {
311 final TypeConstraints constraints = new TypeConstraints();
313 final TypeDefinitionBuilder targetType = getTypedefBuilder(
314 typeToResolve, modules, builder);
315 final TypeConstraints tConstraints = findConstraints(typeToResolve,
316 constraints, modules, builder);
317 targetType.setRanges(tConstraints.getRange());
318 targetType.setLengths(tConstraints.getLength());
319 targetType.setPatterns(tConstraints.getPatterns());
320 targetType.setFractionDigits(tConstraints.getFractionDigits());
325 private TypeDefinitionBuilder resolveTypeUnion(
326 final TypeAwareBuilder typeToResolve,
327 final UnknownType unknownType,
328 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
329 final ModuleBuilder builder) {
330 final TypeConstraints constraints = new TypeConstraints();
332 final TypeDefinitionBuilder targetType = getUnionBuilder(typeToResolve,
333 unknownType, modules, builder);
334 final TypeConstraints tConstraints = findConstraints(typeToResolve,
335 constraints, modules, builder);
336 targetType.setRanges(tConstraints.getRange());
337 targetType.setLengths(tConstraints.getLength());
338 targetType.setPatterns(tConstraints.getPatterns());
339 targetType.setFractionDigits(tConstraints.getFractionDigits());
344 private TypeDefinitionBuilder getTypedefBuilder(
345 final TypeAwareBuilder nodeToResolve,
346 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
347 final ModuleBuilder builder) {
349 final TypeDefinition<?> nodeToResolveBase = nodeToResolve.getType();
350 if (nodeToResolveBase != null
351 && !(nodeToResolveBase instanceof UnknownType)) {
352 return (TypeDefinitionBuilder) nodeToResolve;
355 final UnknownType unknownType = (UnknownType) nodeToResolve.getType();
356 final QName unknownTypeQName = unknownType.getQName();
358 // search for module which contains referenced typedef
359 final ModuleBuilder dependentModule = findDependentModule(modules,
360 builder, unknownTypeQName.getPrefix());
361 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
362 dependentModule, unknownTypeQName.getLocalName());
364 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
365 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
366 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
367 lookedUpBuilderCopy, modules, dependentModule);
371 private TypeDefinitionBuilder getUnionBuilder(
372 final TypeAwareBuilder nodeToResolve,
373 final UnknownType unknownType,
374 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
375 final ModuleBuilder module) {
377 final TypeDefinition<?> baseTypeToResolve = nodeToResolve.getType();
378 if (baseTypeToResolve != null
379 && !(baseTypeToResolve instanceof UnknownType)) {
380 return (TypeDefinitionBuilder) nodeToResolve;
383 final QName unknownTypeQName = unknownType.getQName();
384 // search for module which contains referenced typedef
385 final ModuleBuilder dependentModule = findDependentModule(modules,
386 module, unknownTypeQName.getPrefix());
387 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
388 dependentModule, unknownTypeQName.getLocalName());
390 final TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder(
391 lookedUpBuilder, nodeToResolve instanceof TypeDefinitionBuilder);
392 final TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder(
393 lookedUpBuilderCopy, modules, dependentModule);
397 private TypeDefinitionBuilder copyTypedefBuilder(
398 final TypeDefinitionBuilder old, final boolean seekByTypedefBuilder) {
399 if (old instanceof UnionTypeBuilder) {
400 final UnionTypeBuilder oldUnion = (UnionTypeBuilder) old;
401 final UnionTypeBuilder newUnion = new UnionTypeBuilder();
402 for (TypeDefinition<?> td : oldUnion.getTypes()) {
403 newUnion.setType(td);
405 for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) {
406 newUnion.setType(copyTypedefBuilder(tdb, true));
411 final QName oldName = old.getQName();
412 final QName newName = new QName(oldName.getNamespace(),
413 oldName.getRevision(), oldName.getPrefix(),
414 oldName.getLocalName());
415 final TypeDefinitionBuilder tdb = new TypedefBuilder(newName);
417 tdb.setRanges(old.getRanges());
418 tdb.setLengths(old.getLengths());
419 tdb.setPatterns(old.getPatterns());
420 tdb.setFractionDigits(old.getFractionDigits());
422 final TypeDefinition<?> oldType = old.getType();
423 if (oldType == null) {
424 tdb.setType(old.getTypedef());
426 tdb.setType(oldType);
429 if (!seekByTypedefBuilder) {
430 tdb.setDescription(old.getDescription());
431 tdb.setReference(old.getReference());
432 tdb.setStatus(old.getStatus());
433 tdb.setDefaultValue(old.getDefaultValue());
434 tdb.setUnits(old.getUnits());
439 private TypeDefinitionBuilder resolveCopiedBuilder(
440 final TypeDefinitionBuilder copy,
441 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
442 final ModuleBuilder builder) {
444 if (copy instanceof UnionTypeBuilder) {
445 final UnionTypeBuilder union = (UnionTypeBuilder) copy;
446 final List<TypeDefinition<?>> unionTypes = union.getTypes();
447 final List<UnknownType> toRemove = new ArrayList<UnknownType>();
448 for (TypeDefinition<?> td : unionTypes) {
449 if (td instanceof UnknownType) {
450 final UnknownType unknownType = (UnknownType) td;
451 final TypeDefinitionBuilder resolvedType = resolveTypeUnion(
452 union, unknownType, modules, builder);
453 union.setType(resolvedType);
454 toRemove.add(unknownType);
457 unionTypes.removeAll(toRemove);
462 final TypeDefinition<?> base = copy.getType();
463 final TypeDefinitionBuilder baseTdb = copy.getTypedef();
464 if (base != null && !(base instanceof UnknownType)) {
466 } else if (base instanceof UnknownType) {
467 final UnknownType unknownType = (UnknownType) base;
468 final QName unknownTypeQName = unknownType.getQName();
469 final String unknownTypePrefix = unknownTypeQName.getPrefix();
470 final ModuleBuilder dependentModule = findDependentModule(modules,
471 builder, unknownTypePrefix);
472 final TypeDefinitionBuilder utBuilder = getTypedefBuilder(copy,
473 modules, dependentModule);
474 copy.setType(utBuilder);
476 } else if (base == null && baseTdb != null) {
477 // make a copy of baseTypeDef and call again
478 final TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(
480 final TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder(
481 baseTdbCopy, modules, builder);
482 copy.setType(baseTdbCopyResolved);
485 throw new IllegalStateException(
486 "TypeDefinitionBuilder in unexpected state");
490 private TypeDefinitionBuilder findTypedefBuilder(
491 final QName unknownTypeQName,
492 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
493 final ModuleBuilder builder) {
495 // search for module which contains referenced typedef
496 final ModuleBuilder dependentModule = findDependentModule(modules,
497 builder, unknownTypeQName.getPrefix());
499 final TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilderByName(
500 dependentModule, unknownTypeQName.getLocalName());
502 return copyTypedefBuilder(lookedUpBuilder, true);
505 private TypeConstraints findConstraints(
506 final TypeAwareBuilder nodeToResolve,
507 final TypeConstraints constraints,
508 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
509 final ModuleBuilder builder) {
511 // union type cannot be restricted
512 if (nodeToResolve instanceof UnionTypeBuilder) {
516 // if referenced type is UnknownType again, search recursively with
517 // current constraints
518 final TypeDefinition<?> referencedType = nodeToResolve.getType();
519 List<RangeConstraint> ranges = Collections.emptyList();
520 List<LengthConstraint> lengths = Collections.emptyList();
521 List<PatternConstraint> patterns = Collections.emptyList();
522 Integer fractionDigits = null;
523 if (referencedType == null) {
524 final TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) nodeToResolve;
525 ranges = tdb.getRanges();
526 constraints.addRanges(ranges);
527 lengths = tdb.getLengths();
528 constraints.addLengths(lengths);
529 patterns = tdb.getPatterns();
530 constraints.addPatterns(patterns);
531 fractionDigits = tdb.getFractionDigits();
532 constraints.setFractionDigits(fractionDigits);
534 } else if (referencedType instanceof ExtendedType) {
535 final ExtendedType ext = (ExtendedType) referencedType;
536 ranges = ext.getRanges();
537 constraints.addRanges(ranges);
538 lengths = ext.getLengths();
539 constraints.addLengths(lengths);
540 patterns = ext.getPatterns();
541 constraints.addPatterns(patterns);
542 fractionDigits = ext.getFractionDigits();
543 constraints.setFractionDigits(fractionDigits);
544 return findConstraints(
545 findTypedefBuilder(ext.getQName(), modules, builder),
546 constraints, modules, builder);
547 } else if (referencedType instanceof UnknownType) {
548 final UnknownType unknown = (UnknownType) referencedType;
549 ranges = unknown.getRangeStatements();
550 constraints.addRanges(ranges);
551 lengths = unknown.getLengthStatements();
552 constraints.addLengths(lengths);
553 patterns = unknown.getPatterns();
554 constraints.addPatterns(patterns);
555 fractionDigits = unknown.getFractionDigits();
556 constraints.setFractionDigits(fractionDigits);
558 String unknownTypePrefix = unknown.getQName().getPrefix();
559 if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) {
560 unknownTypePrefix = builder.getPrefix();
562 final ModuleBuilder dependentModule = findDependentModule(modules,
563 builder, unknown.getQName().getPrefix());
564 final TypeDefinitionBuilder utBuilder = findTypedefBuilder(
565 unknown.getQName(), modules, builder);
566 return findConstraints(utBuilder, constraints, modules,
569 // HANDLE BASE YANG TYPE
570 mergeConstraints(referencedType, constraints);
577 * Go through all typedef statements from given module and search for one
581 * typedef statements to search
583 * name of searched typedef
584 * @return typedef with name equals to given name
586 private TypeDefinitionBuilder findTypedefBuilderByName(
587 final ModuleBuilder dependentModule, final String name) {
588 TypeDefinitionBuilder result = null;
589 final Set<TypeDefinitionBuilder> typedefs = dependentModule
590 .getModuleTypedefs();
591 for (TypeDefinitionBuilder td : typedefs) {
592 if (td.getQName().getLocalName().equals(name)) {
597 if (result == null) {
598 throw new YangParseException("Target module '"
599 + dependentModule.getName()
600 + "' does not contain typedef '" + name + "'.");
606 * Pull restriction from referenced type and add them to given constraints
608 * @param referencedType
611 private void mergeConstraints(final TypeDefinition<?> referencedType,
612 final TypeConstraints constraints) {
614 if (referencedType instanceof DecimalTypeDefinition) {
615 constraints.addRanges(((DecimalTypeDefinition) referencedType)
616 .getRangeStatements());
618 .setFractionDigits(((DecimalTypeDefinition) referencedType)
619 .getFractionDigits());
620 } else if (referencedType instanceof IntegerTypeDefinition) {
621 constraints.addRanges(((IntegerTypeDefinition) referencedType)
622 .getRangeStatements());
623 } else if (referencedType instanceof StringTypeDefinition) {
624 constraints.addPatterns(((StringTypeDefinition) referencedType)
626 constraints.addLengths(((StringTypeDefinition) referencedType)
627 .getLengthStatements());
628 } else if (referencedType instanceof BinaryTypeDefinition) {
629 constraints.addLengths(((BinaryTypeDefinition) referencedType)
630 .getLengthConstraints());
635 * Go through all augmentation definitions and resolve them. This method
636 * also finds referenced node and add child nodes to it.
639 * all available modules
641 private void resolveAugments(
642 final Map<String, TreeMap<Date, ModuleBuilder>> modules) {
643 final List<ModuleBuilder> allModulesList = new ArrayList<ModuleBuilder>();
644 final Set<ModuleBuilder> allModulesSet = new HashSet<ModuleBuilder>();
645 for (Map.Entry<String, TreeMap<Date, ModuleBuilder>> entry : modules
647 for (Map.Entry<Date, ModuleBuilder> inner : entry.getValue()
649 allModulesList.add(inner.getValue());
650 allModulesSet.add(inner.getValue());
654 for (int i = 0; i < allModulesList.size(); i++) {
655 final ModuleBuilder module = allModulesList.get(i);
656 // try to resolve augments in module
657 resolveAugment(modules, module);
658 // while all augments are not resolved
659 final Iterator<ModuleBuilder> allModulesIterator = allModulesSet
661 while (!(module.getAugmentsResolved() == module.getAddedAugments()
663 ModuleBuilder nextModule = null;
664 // try resolve other module augments
666 nextModule = allModulesIterator.next();
667 resolveAugment(modules, nextModule);
668 } catch (NoSuchElementException e) {
669 throw new YangParseException(
670 "Failed to resolve augments in module '"
671 + module.getName() + "'.", e);
673 // then try to resolve first module again
674 resolveAugment(modules, module);
679 private void resolveAugment(
680 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
681 final ModuleBuilder module) {
682 if (module.getAugmentsResolved() < module.getAddedAugments().size()) {
683 for (AugmentationSchemaBuilder augmentBuilder : module
684 .getAddedAugments()) {
685 final SchemaPath augmentTargetSchemaPath = augmentBuilder
687 final List<QName> path = augmentTargetSchemaPath.getPath();
690 final QName qname = path.get(i);
691 String prefix = qname.getPrefix();
693 prefix = module.getPrefix();
696 DataSchemaNodeBuilder currentParent = null;
697 final ModuleBuilder dependentModule = findDependentModule(
698 modules, module, prefix);
699 for (DataSchemaNodeBuilder child : dependentModule
701 final QName childQName = child.getQName();
702 if (childQName.getLocalName().equals(qname.getLocalName())) {
703 currentParent = child;
709 for (; i < path.size(); i++) {
710 final QName currentQName = path.get(i);
711 DataSchemaNodeBuilder newParent = null;
712 for (DataSchemaNodeBuilder child : ((ChildNodeBuilder) currentParent)
714 final QName childQName = child.getQName();
715 if (childQName.getLocalName().equals(
716 currentQName.getLocalName())) {
721 if (newParent == null) {
722 break; // node not found, quit search
724 currentParent = newParent;
728 final QName currentQName = currentParent.getQName();
729 final QName lastAugmentPathElement = path.get(path.size() - 1);
731 if (currentQName.getLocalName().equals(
732 lastAugmentPathElement.getLocalName())) {
733 fillAugmentTarget(augmentBuilder,
734 (ChildNodeBuilder) currentParent);
735 ((AugmentationTargetBuilder) currentParent)
736 .addAugmentation(augmentBuilder);
737 module.augmentResolved();
744 * Add all augment's child nodes to given target.
749 private void fillAugmentTarget(final AugmentationSchemaBuilder augment,
750 final ChildNodeBuilder target) {
751 for (DataSchemaNodeBuilder builder : augment.getChildNodes()) {
752 builder.setAugmenting(true);
753 target.addChildNode(builder);
758 * Go through identity statements defined in current module and resolve
759 * their 'base' statement if present.
764 * module being resolved
766 private void resolveIdentities(
767 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
768 final ModuleBuilder module) {
769 final Set<IdentitySchemaNodeBuilder> identities = module
770 .getAddedIdentities();
771 for (IdentitySchemaNodeBuilder identity : identities) {
772 final String baseIdentityName = identity.getBaseIdentityName();
773 if (baseIdentityName != null) {
774 String baseIdentityPrefix = null;
775 String baseIdentityLocalName = null;
776 if (baseIdentityName.contains(":")) {
777 final String[] splitted = baseIdentityName.split(":");
778 baseIdentityPrefix = splitted[0];
779 baseIdentityLocalName = splitted[1];
781 baseIdentityPrefix = module.getPrefix();
782 baseIdentityLocalName = baseIdentityName;
784 final ModuleBuilder dependentModule = findDependentModule(
785 modules, module, baseIdentityPrefix);
787 final Set<IdentitySchemaNodeBuilder> dependentModuleIdentities = dependentModule
788 .getAddedIdentities();
789 for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) {
790 if (idBuilder.getQName().getLocalName()
791 .equals(baseIdentityLocalName)) {
792 identity.setBaseIdentity(idBuilder);
800 * Go through uses statements defined in current module and resolve their
806 * module being resolved
808 private void resolveUses(
809 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
810 final ModuleBuilder module) {
811 final Map<List<String>, UsesNodeBuilder> moduleUses = module
812 .getAddedUsesNodes();
813 for (Map.Entry<List<String>, UsesNodeBuilder> entry : moduleUses
815 final List<String> key = entry.getKey();
816 final UsesNodeBuilder usesNode = entry.getValue();
818 final String groupingName = key.get(key.size() - 1);
820 final List<RefineHolder> refines = usesNode.getRefines();
821 for (RefineHolder refine : refines) {
822 final Refine refineType = refine.getType();
824 final String defaultStr = refine.getDefaultStr();
825 final Boolean mandatory = refine.isMandatory();
826 final MustDefinition must = refine.getMust();
827 final Boolean presence = refine.isPresence();
828 final Integer min = refine.getMinElements();
829 final Integer max = refine.getMaxElements();
831 switch (refineType) {
833 final LeafSchemaNodeBuilder leaf = (LeafSchemaNodeBuilder) getRefineTargetBuilder(
834 groupingName, refine, modules, module);
835 if (defaultStr != null && !("".equals(defaultStr))) {
836 leaf.setDefaultStr(defaultStr);
838 if (mandatory != null) {
839 leaf.getConstraints().setMandatory(mandatory);
842 leaf.getConstraints().addMustDefinition(must);
844 usesNode.addRefineNode(leaf);
847 final ContainerSchemaNodeBuilder container = (ContainerSchemaNodeBuilder) getRefineTargetBuilder(
848 groupingName, refine, modules, module);
849 if (presence != null) {
850 container.setPresence(presence);
853 container.getConstraints().addMustDefinition(must);
855 usesNode.addRefineNode(container);
858 final ListSchemaNodeBuilder list = (ListSchemaNodeBuilder) getRefineTargetBuilder(
859 groupingName, refine, modules, module);
861 list.getConstraints().addMustDefinition(must);
864 list.getConstraints().setMinElements(min);
867 list.getConstraints().setMaxElements(max);
871 final LeafListSchemaNodeBuilder leafList = (LeafListSchemaNodeBuilder) getRefineTargetBuilder(
872 groupingName, refine, modules, module);
874 leafList.getConstraints().addMustDefinition(must);
877 leafList.getConstraints().setMinElements(min);
880 leafList.getConstraints().setMaxElements(max);
884 final ChoiceBuilder choice = (ChoiceBuilder) getRefineTargetBuilder(
885 groupingName, refine, modules, module);
886 if (defaultStr != null) {
887 choice.setDefaultCase(defaultStr);
889 if (mandatory != null) {
890 choice.getConstraints().setMandatory(mandatory);
894 final AnyXmlBuilder anyXml = (AnyXmlBuilder) getRefineTargetBuilder(
895 groupingName, refine, modules, module);
896 if (mandatory != null) {
897 anyXml.getConstraints().setMandatory(mandatory);
900 anyXml.getConstraints().addMustDefinition(must);
909 * Find original builder of refine node and return copy of this builder.
911 * @param groupingPath
912 * path to grouping which contains node to refine
914 * refine object containing informations about refine
919 * @return copy of Builder object of node to be refined if it is present in
920 * grouping, null otherwise
922 private Builder getRefineTargetBuilder(final String groupingPath,
923 final RefineHolder refine,
924 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
925 final ModuleBuilder module) {
926 Builder result = null;
927 final Builder lookedUpBuilder = findRefineTargetBuilder(groupingPath,
928 refine.getName(), modules, module);
929 if (lookedUpBuilder instanceof LeafSchemaNodeBuilder) {
931 .copyLeafBuilder((LeafSchemaNodeBuilder) lookedUpBuilder);
932 } else if (lookedUpBuilder instanceof ContainerSchemaNodeBuilder) {
934 .copyContainerBuilder((ContainerSchemaNodeBuilder) lookedUpBuilder);
935 } else if (lookedUpBuilder instanceof ListSchemaNodeBuilder) {
937 .copyListBuilder((ListSchemaNodeBuilder) lookedUpBuilder);
938 } else if (lookedUpBuilder instanceof LeafListSchemaNodeBuilder) {
940 .copyLeafListBuilder((LeafListSchemaNodeBuilder) lookedUpBuilder);
941 } else if (lookedUpBuilder instanceof ChoiceBuilder) {
943 .copyChoiceBuilder((ChoiceBuilder) lookedUpBuilder);
944 } else if (lookedUpBuilder instanceof AnyXmlBuilder) {
946 .copyAnyXmlBuilder((AnyXmlBuilder) lookedUpBuilder);
948 throw new YangParseException("Target '" + refine.getName()
949 + "' can not be refined");
955 * Find builder of refine node.
957 * @param groupingPath
958 * path to grouping which contains node to refine
959 * @param refineNodeName
960 * name of node to be refined
965 * @return Builder object of refine node if it is present in grouping, null
968 private Builder findRefineTargetBuilder(final String groupingPath,
969 final String refineNodeName,
970 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
971 final ModuleBuilder module) {
972 final SchemaPath path = ParserUtils.parseUsesPath(groupingPath);
973 final List<String> builderPath = new ArrayList<String>();
974 String prefix = null;
975 for (QName qname : path.getPath()) {
976 builderPath.add(qname.getLocalName());
977 prefix = qname.getPrefix();
979 if (prefix == null) {
980 prefix = module.getPrefix();
983 final ModuleBuilder dependentModule = findDependentModule(modules,
985 builderPath.add(0, "grouping");
986 builderPath.add(0, dependentModule.getName());
987 final GroupingBuilder builder = (GroupingBuilder) dependentModule
988 .getNode(builderPath);
990 return builder.getChildNode(refineNodeName);
993 private QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
994 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
996 String baseString = idref.getBaseString();
997 if(baseString.contains(":")) {
998 String[] splittedBase = baseString.split(":");
999 if(splittedBase.length > 2) {
1000 throw new YangParseException("Failed to parse identity base: "+ baseString);
1002 String prefix = splittedBase[0];
1003 String name = splittedBase[1];
1004 ModuleBuilder dependentModule = findDependentModule(modules, module, prefix);
1005 result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1007 result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
1013 * Find dependent module based on given prefix
1016 * all available modules
1020 * target module prefix
1023 private ModuleBuilder findDependentModule(
1024 final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1025 final ModuleBuilder module, final String prefix) {
1026 ModuleBuilder dependentModule = null;
1027 Date dependentModuleRevision = null;
1029 if (prefix.equals(module.getPrefix())) {
1030 dependentModule = module;
1032 final ModuleImport dependentModuleImport = getModuleImport(module,
1034 if (dependentModuleImport == null) {
1035 throw new YangParseException("No import found with prefix '"
1036 + prefix + "' in module " + module.getName() + "'.");
1038 final String dependentModuleName = dependentModuleImport
1040 dependentModuleRevision = dependentModuleImport.getRevision();
1042 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules
1043 .get(dependentModuleName);
1044 if (moduleBuildersByRevision == null) {
1045 throw new YangParseException(
1046 "Failed to find dependent module '"
1047 + dependentModuleName + "' needed by module '"
1048 + module.getName() + "'.");
1050 if (dependentModuleRevision == null) {
1051 dependentModule = moduleBuildersByRevision.lastEntry()
1054 dependentModule = moduleBuildersByRevision
1055 .get(dependentModuleRevision);
1059 if (dependentModule == null) {
1060 throw new YangParseException(
1061 "Failed to find dependent module with prefix '" + prefix
1062 + "' and revision '" + dependentModuleRevision
1065 return dependentModule;
1069 * Get module import referenced by given prefix.
1074 * prefix associated with import
1075 * @return ModuleImport based on given prefix
1077 private ModuleImport getModuleImport(final ModuleBuilder builder,
1078 final String prefix) {
1079 ModuleImport moduleImport = null;
1080 for (ModuleImport mi : builder.getModuleImports()) {
1081 if (mi.getPrefix().equals(prefix)) {
1086 return moduleImport;
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) {
1139 if ((name != null) && (revision != null)) {
1140 for (final Module module : modules) {
1141 if (module.getName().equals(name)
1142 && module.getRevision().equals(revision)) {
1151 public Module findModuleByNamespace(final URI namespace) {
1152 if (namespace != null) {
1153 for (final Module module : modules) {
1154 if (module.getNamespace().equals(namespace)) {