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.yangtools.yang.parser.util;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Date;
14 import java.util.HashSet;
15 import java.util.List;
18 import java.util.TreeMap;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
23 import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
24 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
28 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.Module;
32 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
33 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
34 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
35 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
39 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
40 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
42 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.type.BooleanTypeDefinition;
44 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
45 import org.opendaylight.yangtools.yang.model.api.type.EmptyTypeDefinition;
46 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
47 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
48 import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
49 import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
50 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
51 import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
52 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
53 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
54 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
55 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
56 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
57 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
58 import org.opendaylight.yangtools.yang.model.util.BinaryType;
59 import org.opendaylight.yangtools.yang.model.util.BitsType;
60 import org.opendaylight.yangtools.yang.model.util.BooleanType;
61 import org.opendaylight.yangtools.yang.model.util.Decimal64;
62 import org.opendaylight.yangtools.yang.model.util.EmptyType;
63 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
64 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
65 import org.opendaylight.yangtools.yang.model.util.IdentityrefType;
66 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.model.util.Leafref;
68 import org.opendaylight.yangtools.yang.model.util.UnionType;
69 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
70 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationTargetBuilder;
71 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
72 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
73 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
74 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
75 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingMember;
76 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
77 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
78 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
79 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
80 import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder;
81 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
82 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder.ChoiceNodeImpl;
83 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
84 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder.ChoiceCaseNodeImpl;
85 import org.opendaylight.yangtools.yang.parser.builder.impl.ConstraintsBuilder;
86 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder;
87 import org.opendaylight.yangtools.yang.parser.builder.impl.ContainerSchemaNodeBuilder.ContainerSchemaNodeImpl;
88 import org.opendaylight.yangtools.yang.parser.builder.impl.GroupingBuilderImpl;
89 import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilder;
90 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafListSchemaNodeBuilder;
91 import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
92 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder;
93 import org.opendaylight.yangtools.yang.parser.builder.impl.ListSchemaNodeBuilder.ListSchemaNodeImpl;
94 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
95 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder;
96 import org.opendaylight.yangtools.yang.parser.builder.impl.NotificationBuilder.NotificationDefinitionImpl;
97 import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder;
98 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
99 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
101 public final class ParserUtils {
103 private ParserUtils() {
107 * Create new SchemaPath from given path and qname.
113 public static SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
114 List<QName> path = new ArrayList<>(schemaPath.getPath());
115 path.addAll(Arrays.asList(qname));
116 return new SchemaPath(path, schemaPath.isAbsolute());
120 * Get module import referenced by given prefix.
125 * prefix associated with import
126 * @return ModuleImport based on given prefix
128 public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
129 ModuleImport moduleImport = null;
130 for (ModuleImport mi : builder.getModuleImports()) {
131 if (mi.getPrefix().equals(prefix)) {
140 * Find dependent module based on given prefix
143 * all available modules
147 * target module prefix
149 * current line in yang model
152 public static ModuleBuilder findDependentModuleBuilder(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
153 final ModuleBuilder module, final String prefix, final int line) {
154 ModuleBuilder dependentModule = null;
155 Date dependentModuleRevision = null;
157 if (prefix.equals(module.getPrefix())) {
158 dependentModule = module;
160 final ModuleImport dependentModuleImport = getModuleImport(module, prefix);
161 if (dependentModuleImport == null) {
162 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
164 final String dependentModuleName = dependentModuleImport.getModuleName();
165 dependentModuleRevision = dependentModuleImport.getRevision();
167 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
168 if (moduleBuildersByRevision == null) {
171 if (dependentModuleRevision == null) {
172 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
174 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
177 return dependentModule;
181 * Find module from context based on prefix.
185 * @param currentModule
188 * current prefix used to reference dependent module
190 * current line in yang model
191 * @return module based on given prefix if found in context, null otherwise
193 public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
194 final String prefix, final int line) {
195 TreeMap<Date, Module> modulesByRevision = new TreeMap<Date, Module>();
197 Date dependentModuleRevision = null;
199 final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
200 if (dependentModuleImport == null) {
201 throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
203 final String dependentModuleName = dependentModuleImport.getModuleName();
204 dependentModuleRevision = dependentModuleImport.getRevision();
206 for (Module contextModule : context.getModules()) {
207 if (contextModule.getName().equals(dependentModuleName)) {
208 Date revision = contextModule.getRevision();
209 if (revision == null) {
210 revision = new Date(0L);
212 modulesByRevision.put(revision, contextModule);
217 Module result = null;
218 if (dependentModuleRevision == null) {
219 result = modulesByRevision.get(modulesByRevision.firstKey());
221 result = modulesByRevision.get(dependentModuleRevision);
228 * Find grouping by name.
231 * collection of grouping builders to search
234 * @return grouping with given name if present in collection, null otherwise
236 public static GroupingBuilder findGroupingBuilder(Set<GroupingBuilder> groupings, String name) {
237 for (GroupingBuilder grouping : groupings) {
238 if (grouping.getQName().getLocalName().equals(name)) {
246 * Find grouping by name.
249 * collection of grouping definitions to search
252 * @return grouping with given name if present in collection, null otherwise
254 public static GroupingDefinition findGroupingDefinition(Set<GroupingDefinition> groupings, String name) {
255 for (GroupingDefinition grouping : groupings) {
256 if (grouping.getQName().getLocalName().equals(name)) {
263 public static Set<DataSchemaNodeBuilder> processUsesDataSchemaNode(UsesNodeBuilder usesNode,
264 Set<DataSchemaNodeBuilder> children, SchemaPath parentPath, URI namespace, Date revision, String prefix) {
265 Set<DataSchemaNodeBuilder> newChildren = new HashSet<>();
266 for (DataSchemaNodeBuilder child : children) {
268 DataSchemaNodeBuilder newChild = null;
269 QName qname = new QName(namespace, revision, prefix, child.getQName().getLocalName());
270 if (child instanceof AnyXmlBuilder) {
271 newChild = new AnyXmlBuilder((AnyXmlBuilder) child, qname);
272 } else if (child instanceof ChoiceBuilder) {
273 newChild = new ChoiceBuilder((ChoiceBuilder) child, qname);
274 } else if (child instanceof ContainerSchemaNodeBuilder) {
275 newChild = new ContainerSchemaNodeBuilder((ContainerSchemaNodeBuilder) child, qname);
276 } else if (child instanceof LeafListSchemaNodeBuilder) {
277 newChild = new LeafListSchemaNodeBuilder((LeafListSchemaNodeBuilder) child, qname);
278 } else if (child instanceof LeafSchemaNodeBuilder) {
279 newChild = new LeafSchemaNodeBuilder((LeafSchemaNodeBuilder) child, qname);
280 } else if (child instanceof ListSchemaNodeBuilder) {
281 newChild = new ListSchemaNodeBuilder((ListSchemaNodeBuilder) child, qname);
284 if (newChild == null) {
285 throw new YangParseException(usesNode.getModuleName(), usesNode.getLine(),
286 "Unknown member of target grouping while resolving uses node.");
288 if (newChild instanceof GroupingMember) {
289 ((GroupingMember) newChild).setAddedByUses(true);
292 correctNodePath(newChild, parentPath);
293 newChildren.add(newChild);
300 * Traverse given groupings and create new collection of groupings with
301 * schema path created based on current parent path.
308 * @return collection of new groupings with corrected path
310 public static Set<GroupingBuilder> processUsesGroupings(Set<GroupingBuilder> groupings, SchemaPath parentPath,
311 URI namespace, Date revision, String prefix) {
312 Set<GroupingBuilder> newGroupings = new HashSet<>();
313 for (GroupingBuilder g : groupings) {
314 QName qname = new QName(namespace, revision, prefix, g.getQName().getLocalName());
315 GroupingBuilder newGrouping = new GroupingBuilderImpl(g, qname);
316 newGrouping.setAddedByUses(true);
317 correctNodePath(newGrouping, parentPath);
318 newGroupings.add(newGrouping);
323 public static Set<TypeDefinitionBuilder> processUsesTypedefs(Set<TypeDefinitionBuilder> typedefs,
324 SchemaPath parentPath, URI namespace, Date revision, String prefix) {
325 Set<TypeDefinitionBuilder> newTypedefs = new HashSet<>();
326 for (TypeDefinitionBuilder td : typedefs) {
327 QName qname = new QName(namespace, revision, prefix, td.getQName().getLocalName());
328 TypeDefinitionBuilder newType = new TypeDefinitionBuilderImpl(td, qname);
329 newType.setAddedByUses(true);
330 correctNodePath(newType, parentPath);
331 newTypedefs.add(newType);
336 public static List<UnknownSchemaNodeBuilder> processUsesUnknownNodes(List<UnknownSchemaNodeBuilder> unknownNodes,
337 SchemaPath parentPath, URI namespace, Date revision, String prefix) {
338 List<UnknownSchemaNodeBuilder> newUnknownNodes = new ArrayList<>();
339 for (UnknownSchemaNodeBuilder un : unknownNodes) {
340 QName qname = new QName(namespace, revision, prefix, un.getQName().getLocalName());
341 UnknownSchemaNodeBuilder newUn = new UnknownSchemaNodeBuilder(un, qname);
342 newUn.setAddedByUses(true);
343 correctNodePath(newUn, parentPath);
344 newUnknownNodes.add(newUn);
346 return newUnknownNodes;
350 * Parse XPath string.
354 * @return SchemaPath from given String
356 public static SchemaPath parseXPathString(final String xpathString) {
357 final boolean absolute = xpathString.startsWith("/");
358 final String[] splittedPath = xpathString.split("/");
359 final List<QName> path = new ArrayList<QName>();
361 for (String pathElement : splittedPath) {
362 if (pathElement.length() > 0) {
363 final String[] splittedElement = pathElement.split(":");
364 if (splittedElement.length == 1) {
365 name = new QName(null, null, null, splittedElement[0]);
367 name = new QName(null, null, splittedElement[0], splittedElement[1]);
372 return new SchemaPath(path, absolute);
376 * Add all augment's child nodes to given target.
379 * builder of augment statement
381 * augmentation target node
383 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
384 boolean usesAugment = augment.getParent() instanceof UsesNodeBuilder;
385 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
386 builder.setAugmenting(true);
388 if (builder instanceof GroupingMember) {
389 ((GroupingMember) builder).setAddedByUses(true);
392 correctNodePath(builder, target.getPath());
393 target.addChildNode(builder);
398 * Add all augment's child nodes to given target.
401 * builder of augment statement
403 * augmentation target choice node
405 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
406 boolean usesAugment = augment.getParent() instanceof UsesNodeBuilder;
407 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
408 builder.setAugmenting(true);
410 if (builder instanceof GroupingMember) {
411 ((GroupingMember) builder).setAddedByUses(true);
414 correctNodePath(builder, target.getPath());
415 target.addCase(builder);
419 private static void correctNodePath(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath) {
421 List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
422 targetNodePath.add(node.getQName());
423 node.setPath(new SchemaPath(targetNodePath, true));
425 // set correct path for all child nodes
426 if (node instanceof DataNodeContainerBuilder) {
427 DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
428 for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
429 correctNodePath(child, node.getPath());
433 // set correct path for all cases
434 if (node instanceof ChoiceBuilder) {
435 ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
436 for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
437 correctNodePath(choiceCaseBuilder, node.getPath());
441 // if node can contains type, correct path for this type too
442 if (node instanceof TypeAwareBuilder) {
443 TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) node;
444 correctTypeAwareNodePath(nodeBuilder, parentSchemaPath);
449 * Repair schema path of node type.
452 * node which contains type statement
453 * @param parentSchemaPath
454 * schema path of parent node
456 private static void correctTypeAwareNodePath(final TypeAwareBuilder node, final SchemaPath parentSchemaPath) {
457 final QName nodeBuilderQName = node.getQName();
458 final TypeDefinition<?> nodeType = node.getType();
461 List<LengthConstraint> lengths = null;
462 List<PatternConstraint> patterns = null;
463 List<RangeConstraint> ranges = null;
465 if (nodeType != null) {
466 if (nodeType instanceof ExtendedType) {
467 ExtendedType et = (ExtendedType) nodeType;
468 if (nodeType.getQName().getLocalName().equals(nodeType.getBaseType().getQName().getLocalName())) {
469 fd = et.getFractionDigits();
470 lengths = et.getLengths();
471 patterns = et.getPatterns();
472 ranges = et.getRanges();
473 if (!hasConstraints(fd, lengths, patterns, ranges)) {
478 TypeDefinition<?> newType = createCorrectTypeDefinition(parentSchemaPath, nodeBuilderQName, nodeType);
479 node.setType(newType);
481 TypeDefinitionBuilder nodeBuilderTypedef = node.getTypedef();
483 fd = nodeBuilderTypedef.getFractionDigits();
484 lengths = nodeBuilderTypedef.getLengths();
485 patterns = nodeBuilderTypedef.getPatterns();
486 ranges = nodeBuilderTypedef.getRanges();
488 String tdbTypeName = nodeBuilderTypedef.getQName().getLocalName();
489 String baseTypeName = null;
490 if (nodeBuilderTypedef.getType() == null) {
491 baseTypeName = nodeBuilderTypedef.getTypedef().getQName().getLocalName();
493 baseTypeName = nodeBuilderTypedef.getType().getQName().getLocalName();
495 if (!(tdbTypeName.equals(baseTypeName))) {
499 if (!hasConstraints(fd, lengths, patterns, ranges)) {
503 SchemaPath newSchemaPath = createSchemaPath(nodeBuilderTypedef.getPath(), nodeBuilderQName,
504 nodeBuilderTypedef.getQName());
505 nodeBuilderTypedef.setPath(newSchemaPath);
510 * Check if there are some constraints.
517 * pattern constraints
520 * @return true, if any of constraints are present, false otherwise
522 private static boolean hasConstraints(final Integer fd, final List<LengthConstraint> lengths,
523 final List<PatternConstraint> patterns, final List<RangeConstraint> ranges) {
524 if (fd == null && (lengths == null || lengths.isEmpty()) && (patterns == null || patterns.isEmpty())
525 && (ranges == null || ranges.isEmpty())) {
532 private static TypeDefinition<?> createCorrectTypeDefinition(SchemaPath parentSchemaPath, QName nodeQName,
533 TypeDefinition<?> nodeType) {
534 TypeDefinition<?> result = null;
536 if (nodeType != null) {
537 QName nodeTypeQName = nodeType.getQName();
538 SchemaPath newSchemaPath = createSchemaPath(parentSchemaPath, nodeQName, nodeTypeQName);
540 if (nodeType instanceof BinaryTypeDefinition) {
541 BinaryTypeDefinition binType = (BinaryTypeDefinition) nodeType;
543 // List<Byte> bytes = (List<Byte>) binType.getDefaultValue();
544 // workaround to get rid of 'Unchecked cast' warning
545 List<Byte> bytes = new ArrayList<Byte>();
546 Object defaultValue = binType.getDefaultValue();
547 if (defaultValue instanceof List) {
548 for (Object o : List.class.cast(defaultValue)) {
549 if (o instanceof Byte) {
554 result = new BinaryType(newSchemaPath, bytes);
555 } else if (nodeType instanceof BitsTypeDefinition) {
556 BitsTypeDefinition bitsType = (BitsTypeDefinition) nodeType;
557 result = new BitsType(newSchemaPath, bitsType.getBits());
558 } else if (nodeType instanceof BooleanTypeDefinition) {
559 result = new BooleanType(newSchemaPath);
560 } else if (nodeType instanceof DecimalTypeDefinition) {
561 DecimalTypeDefinition decimalType = (DecimalTypeDefinition) nodeType;
562 result = new Decimal64(newSchemaPath, decimalType.getFractionDigits());
563 } else if (nodeType instanceof EmptyTypeDefinition) {
564 result = new EmptyType(newSchemaPath);
565 } else if (nodeType instanceof EnumTypeDefinition) {
566 EnumTypeDefinition enumType = (EnumTypeDefinition) nodeType;
567 result = new EnumerationType(newSchemaPath, (EnumPair) enumType.getDefaultValue(), enumType.getValues());
568 } else if (nodeType instanceof IdentityrefTypeDefinition) {
569 IdentityrefTypeDefinition idrefType = (IdentityrefTypeDefinition) nodeType;
570 result = new IdentityrefType(idrefType.getIdentity(), newSchemaPath);
571 } else if (nodeType instanceof InstanceIdentifierTypeDefinition) {
572 InstanceIdentifierTypeDefinition instIdType = (InstanceIdentifierTypeDefinition) nodeType;
573 return new InstanceIdentifier(newSchemaPath, instIdType.getPathStatement(),
574 instIdType.requireInstance());
575 } else if (nodeType instanceof StringTypeDefinition) {
576 result = TypeUtils.createNewStringType(parentSchemaPath, nodeQName, (StringTypeDefinition) nodeType);
577 } else if (nodeType instanceof IntegerTypeDefinition) {
578 result = TypeUtils.createNewIntType(parentSchemaPath, nodeQName, (IntegerTypeDefinition) nodeType);
579 } else if (nodeType instanceof UnsignedIntegerTypeDefinition) {
580 result = TypeUtils.createNewUintType(parentSchemaPath, nodeQName,
581 (UnsignedIntegerTypeDefinition) nodeType);
582 } else if (nodeType instanceof LeafrefTypeDefinition) {
583 result = new Leafref(newSchemaPath, ((LeafrefTypeDefinition) nodeType).getPathStatement());
584 } else if (nodeType instanceof UnionTypeDefinition) {
585 UnionTypeDefinition unionType = (UnionTypeDefinition) nodeType;
586 return new UnionType(newSchemaPath, unionType.getTypes());
587 } else if (nodeType instanceof ExtendedType) {
588 ExtendedType extType = (ExtendedType) nodeType;
589 result = TypeUtils.createNewExtendedType(extType, newSchemaPath);
596 * Create LeafSchemaNodeBuilder from given LeafSchemaNode.
599 * leaf from which to create builder
602 * current module name
605 * @return leaf builder based on given leaf node
607 public static LeafSchemaNodeBuilder createLeafBuilder(LeafSchemaNode leaf, QName qname, String moduleName, int line) {
608 final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(moduleName, line, qname, leaf.getPath());
609 convertDataSchemaNode(leaf, builder);
610 builder.setConfiguration(leaf.isConfiguration());
611 final TypeDefinition<?> type = leaf.getType();
612 builder.setType(type);
613 builder.setPath(leaf.getPath());
614 builder.setUnknownNodes(leaf.getUnknownSchemaNodes());
615 builder.setDefaultStr(leaf.getDefault());
616 builder.setUnits(leaf.getUnits());
621 * Create ContainerSchemaNodeBuilder from given ContainerSchemaNode.
626 * current module name
628 * current line in module
629 * @return container builder based on given container node
631 public static ContainerSchemaNodeBuilder createContainer(ContainerSchemaNode container, QName qname,
632 String moduleName, int line) {
633 final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(moduleName, line, qname,
634 container.getPath());
635 convertDataSchemaNode(container, builder);
636 builder.setConfiguration(container.isConfiguration());
637 builder.setUnknownNodes(container.getUnknownSchemaNodes());
638 builder.setChildNodes(container.getChildNodes());
639 builder.setGroupings(container.getGroupings());
640 builder.setTypedefs(container.getTypeDefinitions());
641 builder.setAugmentations(container.getAvailableAugmentations());
642 builder.setUsesnodes(container.getUses());
643 builder.setPresence(container.isPresenceContainer());
648 * Create ListSchemaNodeBuilder from given ListSchemaNode.
653 * current module name
655 * current line in module
656 * @return list builder based on given list node
658 public static ListSchemaNodeBuilder createList(ListSchemaNode list, QName qname, String moduleName, int line) {
659 ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(moduleName, line, qname, list.getPath());
660 convertDataSchemaNode(list, builder);
661 builder.setConfiguration(list.isConfiguration());
662 builder.setUnknownNodes(list.getUnknownSchemaNodes());
663 builder.setTypedefs(list.getTypeDefinitions());
664 builder.setChildNodes(list.getChildNodes());
665 builder.setGroupings(list.getGroupings());
666 builder.setAugmentations(list.getAvailableAugmentations());
667 builder.setUsesnodes(list.getUses());
668 builder.setUserOrdered(builder.isUserOrdered());
673 * Create LeafListSchemaNodeBuilder from given LeafListSchemaNode.
678 * current module name
680 * current line in module
681 * @return leaf-list builder based on given leaf-list node
683 public static LeafListSchemaNodeBuilder createLeafList(LeafListSchemaNode leafList, QName qname, String moduleName,
685 final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(moduleName, line, qname,
687 convertDataSchemaNode(leafList, builder);
688 builder.setConfiguration(leafList.isConfiguration());
689 builder.setType(leafList.getType());
690 builder.setUnknownNodes(leafList.getUnknownSchemaNodes());
691 builder.setUserOrdered(leafList.isUserOrdered());
696 * Create ChoiceBuilder from given ChoiceNode.
701 * current module name
703 * current line in module
704 * @return choice builder based on given choice node
706 public static ChoiceBuilder createChoice(ChoiceNode choice, QName qname, String moduleName, int line) {
707 final ChoiceBuilder builder = new ChoiceBuilder(moduleName, line, qname);
708 convertDataSchemaNode(choice, builder);
709 builder.setConfiguration(choice.isConfiguration());
710 builder.setCases(choice.getCases());
711 builder.setUnknownNodes(choice.getUnknownSchemaNodes());
712 builder.setDefaultCase(choice.getDefaultCase());
717 * Create AnyXmlBuilder from given AnyXmlSchemaNode.
722 * current module name
724 * current line in module
725 * @return anyxml builder based on given anyxml node
727 public static AnyXmlBuilder createAnyXml(AnyXmlSchemaNode anyxml, QName qname, String moduleName, int line) {
728 final AnyXmlBuilder builder = new AnyXmlBuilder(moduleName, line, qname, anyxml.getPath());
729 convertDataSchemaNode(anyxml, builder);
730 builder.setConfiguration(anyxml.isConfiguration());
731 builder.setUnknownNodes(anyxml.getUnknownSchemaNodes());
736 * Create GroupingBuilder from given GroupingDefinition.
741 * current module name
743 * current line in module
744 * @return grouping builder based on given grouping node
746 public static GroupingBuilder createGrouping(GroupingDefinition grouping, QName qname, String moduleName, int line) {
747 final GroupingBuilderImpl builder = new GroupingBuilderImpl(moduleName, line, qname);
748 builder.setPath(grouping.getPath());
749 builder.setChildNodes(grouping.getChildNodes());
750 builder.setGroupings(grouping.getGroupings());
751 builder.setTypedefs(grouping.getTypeDefinitions());
752 builder.setUsesnodes(grouping.getUses());
753 builder.setUnknownNodes(grouping.getUnknownSchemaNodes());
754 builder.setDescription(grouping.getDescription());
755 builder.setReference(grouping.getReference());
756 builder.setStatus(grouping.getStatus());
761 * Create TypeDefinitionBuilder from given ExtendedType.
766 * current module name
768 * current line in module
769 * @return typedef builder based on given typedef node
771 public static TypeDefinitionBuilder createTypedef(ExtendedType typedef, QName qname, String moduleName, int line) {
772 final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(moduleName, line, qname);
773 builder.setPath(typedef.getPath());
774 builder.setDefaultValue(typedef.getDefaultValue());
775 builder.setUnits(typedef.getUnits());
776 builder.setDescription(typedef.getDescription());
777 builder.setReference(typedef.getReference());
778 builder.setStatus(typedef.getStatus());
779 builder.setRanges(typedef.getRanges());
780 builder.setLengths(typedef.getLengths());
781 builder.setPatterns(typedef.getPatterns());
782 builder.setFractionDigits(typedef.getFractionDigits());
783 final TypeDefinition<?> type = typedef.getBaseType();
784 builder.setType(type);
785 builder.setUnits(typedef.getUnits());
786 builder.setUnknownNodes(typedef.getUnknownSchemaNodes());
791 * Create UnknownSchemaNodeBuilder from given UnknownSchemaNode.
796 * current module name
798 * current line in module
799 * @return unknown node builder based on given unknown node
801 public static UnknownSchemaNodeBuilder createUnknownSchemaNode(UnknownSchemaNode unknownNode, QName qname,
802 String moduleName, int line) {
803 final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(moduleName, line, qname);
804 builder.setPath(unknownNode.getPath());
805 builder.setUnknownNodes(unknownNode.getUnknownSchemaNodes());
806 builder.setDescription(unknownNode.getDescription());
807 builder.setReference(unknownNode.getReference());
808 builder.setStatus(unknownNode.getStatus());
809 builder.setAddedByUses(unknownNode.isAddedByUses());
810 builder.setNodeType(unknownNode.getNodeType());
811 builder.setNodeParameter(unknownNode.getNodeParameter());
816 * Set DataSchemaNode arguments to builder object
819 * node from which arguments should be read
821 * builder to which arguments should be set
823 private static void convertDataSchemaNode(DataSchemaNode node, DataSchemaNodeBuilder builder) {
824 builder.setPath(node.getPath());
825 builder.setDescription(node.getDescription());
826 builder.setReference(node.getReference());
827 builder.setStatus(node.getStatus());
828 builder.setAugmenting(node.isAugmenting());
829 copyConstraintsFromDefinition(node.getConstraints(), builder.getConstraints());
833 * Copy constraints from constraints definition to constraints builder.
835 * @param nodeConstraints
836 * definition from which constraints will be copied
838 * builder to which constraints will be added
840 private static void copyConstraintsFromDefinition(final ConstraintDefinition nodeConstraints,
841 final ConstraintsBuilder constraints) {
842 final RevisionAwareXPath when = nodeConstraints.getWhenCondition();
843 final Set<MustDefinition> must = nodeConstraints.getMustConstraints();
846 constraints.addWhenCondition(when.toString());
849 for (MustDefinition md : must) {
850 constraints.addMustDefinition(md);
853 constraints.setMandatory(nodeConstraints.isMandatory());
854 constraints.setMinElements(nodeConstraints.getMinElements());
855 constraints.setMaxElements(nodeConstraints.getMaxElements());
858 public static void processAugmentationOnContext(final AugmentationSchemaBuilder augmentBuilder,
859 final List<QName> path, final ModuleBuilder module, final String prefix, final int line,
860 final SchemaContext context) {
861 final Module dependentModule = findModuleFromContext(context, module, prefix, line);
862 if (dependentModule == null) {
863 throw new YangParseException(module.getName(), line, "Failed to find referenced module with prefix "
866 SchemaNode node = dependentModule.getDataChildByName(path.get(0).getLocalName());
868 Set<NotificationDefinition> notifications = dependentModule.getNotifications();
869 for (NotificationDefinition ntf : notifications) {
870 if (ntf.getQName().getLocalName().equals(path.get(0).getLocalName())) {
880 for (int i = 1; i < path.size(); i++) {
881 if (node instanceof DataNodeContainer) {
882 DataNodeContainer ref = (DataNodeContainer) node;
883 node = ref.getDataChildByName(path.get(i).getLocalName());
890 if (node instanceof ContainerSchemaNodeImpl) {
891 // includes container, input and output statement
892 ContainerSchemaNodeImpl c = (ContainerSchemaNodeImpl) node;
893 ContainerSchemaNodeBuilder cb = c.toBuilder();
894 fillAugmentTarget(augmentBuilder, cb);
895 ((AugmentationTargetBuilder) cb).addAugmentation(augmentBuilder);
896 SchemaPath oldPath = cb.getPath();
898 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
899 augmentBuilder.setResolved(true);
900 module.augmentResolved();
901 } else if (node instanceof ListSchemaNodeImpl) {
902 ListSchemaNodeImpl l = (ListSchemaNodeImpl) node;
903 ListSchemaNodeBuilder lb = l.toBuilder();
904 fillAugmentTarget(augmentBuilder, lb);
905 ((AugmentationTargetBuilder) lb).addAugmentation(augmentBuilder);
906 SchemaPath oldPath = lb.getPath();
908 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
909 augmentBuilder.setResolved(true);
910 module.augmentResolved();
911 } else if (node instanceof ChoiceNodeImpl) {
912 ChoiceNodeImpl ch = (ChoiceNodeImpl) node;
913 ChoiceBuilder chb = ch.toBuilder();
914 fillAugmentTarget(augmentBuilder, chb);
915 ((AugmentationTargetBuilder) chb).addAugmentation(augmentBuilder);
916 SchemaPath oldPath = chb.getPath();
918 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
919 augmentBuilder.setResolved(true);
920 module.augmentResolved();
921 } else if (node instanceof ChoiceCaseNodeImpl) {
922 ChoiceCaseNodeImpl chc = (ChoiceCaseNodeImpl) node;
923 ChoiceCaseBuilder chcb = chc.toBuilder();
924 fillAugmentTarget(augmentBuilder, chcb);
925 ((AugmentationTargetBuilder) chcb).addAugmentation(augmentBuilder);
926 SchemaPath oldPath = chcb.getPath();
928 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
929 augmentBuilder.setResolved(true);
930 module.augmentResolved();
931 } else if (node instanceof NotificationDefinitionImpl) {
932 NotificationDefinitionImpl nd = (NotificationDefinitionImpl) node;
933 NotificationBuilder nb = nd.toBuilder();
934 fillAugmentTarget(augmentBuilder, nb);
935 ((AugmentationTargetBuilder) nb).addAugmentation(augmentBuilder);
936 SchemaPath oldPath = nb.getPath();
938 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
939 augmentBuilder.setResolved(true);
940 module.augmentResolved();
942 throw new YangParseException(module.getName(), line, "Target of type " + node.getClass()
943 + " cannot be augmented.");
947 public static void processAugmentation(final AugmentationSchemaBuilder augmentBuilder, final List<QName> path,
948 final ModuleBuilder module, final ModuleBuilder dependentModuleBuilder) {
949 DataSchemaNodeBuilder currentParent = null;
950 for (DataSchemaNodeBuilder child : dependentModuleBuilder.getChildNodeBuilders()) {
951 final QName childQName = child.getQName();
952 if (childQName.getLocalName().equals(path.get(0).getLocalName())) {
953 currentParent = child;
958 if (currentParent == null) {
962 for (int i = 1; i < path.size(); i++) {
963 final QName currentQName = path.get(i);
964 DataSchemaNodeBuilder newParent = null;
965 if (currentParent instanceof DataNodeContainerBuilder) {
966 for (DataSchemaNodeBuilder child : ((DataNodeContainerBuilder) currentParent).getChildNodeBuilders()) {
967 final QName childQName = child.getQName();
968 if (childQName.getLocalName().equals(currentQName.getLocalName())) {
973 } else if (currentParent instanceof ChoiceBuilder) {
974 for (ChoiceCaseBuilder caseBuilder : ((ChoiceBuilder) currentParent).getCases()) {
975 final QName caseQName = caseBuilder.getQName();
976 if (caseQName.getLocalName().equals(currentQName.getLocalName())) {
977 newParent = caseBuilder;
983 if (newParent == null) {
984 break; // node not found, quit search
986 currentParent = newParent;
990 final String currentName = currentParent.getQName().getLocalName();
991 final String lastAugmentPathElementName = path.get(path.size() - 1).getLocalName();
992 if (currentName.equals(lastAugmentPathElementName)) {
994 if (currentParent instanceof ChoiceBuilder) {
995 fillAugmentTarget(augmentBuilder, (ChoiceBuilder) currentParent);
997 fillAugmentTarget(augmentBuilder, (DataNodeContainerBuilder) currentParent);
999 ((AugmentationTargetBuilder) currentParent).addAugmentation(augmentBuilder);
1000 SchemaPath oldPath = currentParent.getPath();
1001 augmentBuilder.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
1002 augmentBuilder.setResolved(true);
1003 module.augmentResolved();
1008 * Search given modules for grouping by name defined in uses node.
1010 * @param usesBuilder
1011 * builder of uses statement
1013 * all loaded modules
1016 * @return grouping with given name if found, null otherwise
1018 public static GroupingBuilder getTargetGroupingFromModules(final UsesNodeBuilder usesBuilder,
1019 final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module) {
1020 final int line = usesBuilder.getLine();
1021 final String groupingString = usesBuilder.getGroupingName();
1022 String groupingPrefix;
1023 String groupingName;
1025 if (groupingString.contains(":")) {
1026 String[] splitted = groupingString.split(":");
1027 if (splitted.length != 2 || groupingString.contains("/")) {
1028 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1030 groupingPrefix = splitted[0];
1031 groupingName = splitted[1];
1033 groupingPrefix = module.getPrefix();
1034 groupingName = groupingString;
1037 ModuleBuilder dependentModule = null;
1038 if (groupingPrefix.equals(module.getPrefix())) {
1039 dependentModule = module;
1041 dependentModule = findDependentModuleBuilder(modules, module, groupingPrefix, line);
1044 if (dependentModule == null) {
1048 GroupingBuilder result = null;
1049 Set<GroupingBuilder> groupings = dependentModule.getGroupingBuilders();
1050 result = findGroupingBuilder(groupings, groupingName);
1051 if (result != null) {
1055 Builder parent = usesBuilder.getParent();
1057 while (parent != null) {
1058 if (parent instanceof DataNodeContainerBuilder) {
1059 groupings = ((DataNodeContainerBuilder) parent).getGroupingBuilders();
1060 } else if (parent instanceof RpcDefinitionBuilder) {
1061 groupings = ((RpcDefinitionBuilder) parent).getGroupings();
1063 result = findGroupingBuilder(groupings, groupingName);
1064 if (result == null) {
1065 parent = parent.getParent();
1071 if (result == null) {
1072 throw new YangParseException(module.getName(), line, "Referenced grouping '" + groupingName
1079 * Search context for grouping by name defined in uses node.
1081 * @param usesBuilder
1082 * builder of uses statement
1086 * SchemaContext containing already resolved modules
1087 * @return grouping with given name if found, null otherwise
1089 public static GroupingDefinition getTargetGroupingFromContext(final UsesNodeBuilder usesBuilder,
1090 final ModuleBuilder module, final SchemaContext context) {
1091 final int line = usesBuilder.getLine();
1092 String groupingString = usesBuilder.getGroupingName();
1093 String groupingPrefix;
1094 String groupingName;
1096 if (groupingString.contains(":")) {
1097 String[] splitted = groupingString.split(":");
1098 if (splitted.length != 2 || groupingString.contains("/")) {
1099 throw new YangParseException(module.getName(), line, "Invalid name of target grouping");
1101 groupingPrefix = splitted[0];
1102 groupingName = splitted[1];
1104 groupingPrefix = module.getPrefix();
1105 groupingName = groupingString;
1108 Module dependentModule = findModuleFromContext(context, module, groupingPrefix, line);
1109 return findGroupingDefinition(dependentModule.getGroupings(), groupingName);
1112 public static QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
1113 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
1114 QName result = null;
1115 String baseString = idref.getBaseString();
1116 if (baseString.contains(":")) {
1117 String[] splittedBase = baseString.split(":");
1118 if (splittedBase.length > 2) {
1119 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
1122 String prefix = splittedBase[0];
1123 String name = splittedBase[1];
1124 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
1125 result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
1127 result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);