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.TypeDefinitionBuilderImpl;
98 import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilder;
100 public final class ParserUtils {
102 private ParserUtils() {
106 * Create new SchemaPath from given path and qname.
112 public static SchemaPath createSchemaPath(SchemaPath schemaPath, QName... qname) {
113 List<QName> path = new ArrayList<>(schemaPath.getPath());
114 path.addAll(Arrays.asList(qname));
115 return new SchemaPath(path, schemaPath.isAbsolute());
119 * Get module import referenced by given prefix.
124 * prefix associated with import
125 * @return ModuleImport based on given prefix
127 public static ModuleImport getModuleImport(final ModuleBuilder builder, final String prefix) {
128 ModuleImport moduleImport = null;
129 for (ModuleImport mi : builder.getModuleImports()) {
130 if (mi.getPrefix().equals(prefix)) {
139 * Find dependent module based on given prefix
142 * all available modules
146 * target module prefix
148 * current line in yang model
149 * @return module builder if found, null otherwise
151 public static ModuleBuilder findDependentModuleBuilder(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
152 final ModuleBuilder module, final String prefix, final int line) {
153 ModuleBuilder dependentModule = null;
154 Date dependentModuleRevision = null;
156 if (prefix.equals(module.getPrefix())) {
157 dependentModule = module;
159 final ModuleImport dependentModuleImport = getModuleImport(module, prefix);
160 if (dependentModuleImport == null) {
161 throw new YangParseException(module.getName(), line, "No import found with prefix '" + prefix + "'.");
163 final String dependentModuleName = dependentModuleImport.getModuleName();
164 dependentModuleRevision = dependentModuleImport.getRevision();
166 final TreeMap<Date, ModuleBuilder> moduleBuildersByRevision = modules.get(dependentModuleName);
167 if (moduleBuildersByRevision == null) {
170 if (dependentModuleRevision == null) {
171 dependentModule = moduleBuildersByRevision.lastEntry().getValue();
173 dependentModule = moduleBuildersByRevision.get(dependentModuleRevision);
176 return dependentModule;
180 * Find module from context based on prefix.
184 * @param currentModule
187 * current prefix used to reference dependent module
189 * current line in yang model
190 * @return module based on given prefix if found in context, null otherwise
192 public static Module findModuleFromContext(final SchemaContext context, final ModuleBuilder currentModule,
193 final String prefix, final int line) {
194 TreeMap<Date, Module> modulesByRevision = new TreeMap<Date, Module>();
196 final ModuleImport dependentModuleImport = ParserUtils.getModuleImport(currentModule, prefix);
197 if (dependentModuleImport == null) {
198 throw new YangParseException(currentModule.getName(), line, "No import found with prefix '" + prefix + "'.");
200 final String dependentModuleName = dependentModuleImport.getModuleName();
201 final Date dependentModuleRevision = dependentModuleImport.getRevision();
203 for (Module contextModule : context.getModules()) {
204 if (contextModule.getName().equals(dependentModuleName)) {
205 Date revision = contextModule.getRevision();
206 if (revision == null) {
207 revision = new Date(0L);
209 modulesByRevision.put(revision, contextModule);
214 Module result = null;
215 if (dependentModuleRevision == null) {
216 result = modulesByRevision.get(modulesByRevision.firstKey());
218 result = modulesByRevision.get(dependentModuleRevision);
225 * Parse XPath string.
229 * @return SchemaPath from given String
231 public static SchemaPath parseXPathString(final String xpathString) {
232 final boolean absolute = xpathString.startsWith("/");
233 final String[] splittedPath = xpathString.split("/");
234 final List<QName> path = new ArrayList<QName>();
236 for (String pathElement : splittedPath) {
237 if (pathElement.length() > 0) {
238 final String[] splittedElement = pathElement.split(":");
239 if (splittedElement.length == 1) {
240 name = new QName(null, null, null, splittedElement[0]);
242 name = new QName(null, null, splittedElement[0], splittedElement[1]);
247 return new SchemaPath(path, absolute);
251 * Add all augment's child nodes to given target.
254 * builder of augment statement
256 * augmentation target node
258 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final DataNodeContainerBuilder target) {
259 for (DataSchemaNodeBuilder child : augment.getChildNodeBuilders()) {
260 DataSchemaNodeBuilder childCopy = CopyUtils.copy(child, target, false);
261 childCopy.setAugmenting(true);
262 correctNodePath(child, target.getPath());
263 correctNodePath(childCopy, target.getPath());
265 target.addChildNode(childCopy);
266 } catch(YangParseException e) {
267 // more descriptive message
268 throw new YangParseException(augment.getModuleName(), augment.getLine(), "Failed to perform augmentation: "+ e.getMessage());
272 for (UsesNodeBuilder usesNode : augment.getUsesNodes()) {
273 target.addUsesNode(CopyUtils.copyUses(usesNode, target));
278 * Add all augment's child nodes to given target.
281 * builder of augment statement
283 * augmentation target choice node
285 public static void fillAugmentTarget(final AugmentationSchemaBuilder augment, final ChoiceBuilder target) {
286 for (DataSchemaNodeBuilder builder : augment.getChildNodeBuilders()) {
287 DataSchemaNodeBuilder childCopy = CopyUtils.copy(builder, target, false);
288 childCopy.setAugmenting(true);
289 correctNodePath(builder, target.getPath());
290 correctNodePath(childCopy, target.getPath());
291 target.addCase(childCopy);
293 for (UsesNodeBuilder usesNode : augment.getUsesNodes()) {
294 if (usesNode != null) {
295 throw new YangParseException(augment.getModuleName(), augment.getLine(),
296 "Error in augment parsing: cannot augment uses to choice");
302 static void correctNodePath(final SchemaNodeBuilder node, final SchemaPath parentSchemaPath) {
304 List<QName> targetNodePath = new ArrayList<QName>(parentSchemaPath.getPath());
305 targetNodePath.add(node.getQName());
306 node.setPath(new SchemaPath(targetNodePath, true));
308 // set correct path for all child nodes
309 if (node instanceof DataNodeContainerBuilder) {
310 DataNodeContainerBuilder dataNodeContainer = (DataNodeContainerBuilder) node;
311 for (DataSchemaNodeBuilder child : dataNodeContainer.getChildNodeBuilders()) {
312 correctNodePath(child, node.getPath());
316 // set correct path for all cases
317 if (node instanceof ChoiceBuilder) {
318 ChoiceBuilder choiceBuilder = (ChoiceBuilder) node;
319 for (ChoiceCaseBuilder choiceCaseBuilder : choiceBuilder.getCases()) {
320 correctNodePath(choiceCaseBuilder, node.getPath());
324 // if node can contains type, correct path for this type too
325 if (node instanceof TypeAwareBuilder) {
326 TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) node;
327 correctTypeAwareNodePath(nodeBuilder, node.getPath());
332 * Repair schema path of node type.
335 * node which contains type statement
336 * @param parentSchemaPath
337 * schema path of parent node
339 private static void correctTypeAwareNodePath(final TypeAwareBuilder node, final SchemaPath parentSchemaPath) {
340 final QName nodeBuilderQName = node.getQName();
341 final TypeDefinition<?> nodeType = node.getType();
344 List<LengthConstraint> lengths = null;
345 List<PatternConstraint> patterns = null;
346 List<RangeConstraint> ranges = null;
348 if (nodeType != null) {
349 if (nodeType instanceof ExtendedType) {
350 ExtendedType et = (ExtendedType) nodeType;
351 if (nodeType.getQName().getLocalName().equals(nodeType.getBaseType().getQName().getLocalName())) {
352 fd = et.getFractionDigits();
353 lengths = et.getLengths();
354 patterns = et.getPatterns();
355 ranges = et.getRanges();
356 if (!hasConstraints(fd, lengths, patterns, ranges)) {
361 TypeDefinition<?> newType = createCorrectTypeDefinition(parentSchemaPath, nodeBuilderQName, nodeType);
362 node.setType(newType);
364 TypeDefinitionBuilder nodeBuilderTypedef = node.getTypedef();
366 fd = nodeBuilderTypedef.getFractionDigits();
367 lengths = nodeBuilderTypedef.getLengths();
368 patterns = nodeBuilderTypedef.getPatterns();
369 ranges = nodeBuilderTypedef.getRanges();
371 String tdbTypeName = nodeBuilderTypedef.getQName().getLocalName();
372 String baseTypeName = null;
373 if (nodeBuilderTypedef.getType() == null) {
374 baseTypeName = nodeBuilderTypedef.getTypedef().getQName().getLocalName();
376 baseTypeName = nodeBuilderTypedef.getType().getQName().getLocalName();
378 if (!(tdbTypeName.equals(baseTypeName))) {
382 if (!hasConstraints(fd, lengths, patterns, ranges)) {
386 SchemaPath newSchemaPath = createSchemaPath(nodeBuilderTypedef.getPath(), nodeBuilderQName,
387 nodeBuilderTypedef.getQName());
388 nodeBuilderTypedef.setPath(newSchemaPath);
393 * Check if there are some constraints.
400 * pattern constraints
403 * @return true, if any of constraints are present, false otherwise
405 private static boolean hasConstraints(final Integer fd, final List<LengthConstraint> lengths,
406 final List<PatternConstraint> patterns, final List<RangeConstraint> ranges) {
407 if (fd == null && (lengths == null || lengths.isEmpty()) && (patterns == null || patterns.isEmpty())
408 && (ranges == null || ranges.isEmpty())) {
415 private static TypeDefinition<?> createCorrectTypeDefinition(SchemaPath parentSchemaPath, QName nodeQName,
416 TypeDefinition<?> nodeType) {
417 TypeDefinition<?> result = null;
419 if (nodeType != null) {
420 QName nodeTypeQName = nodeType.getQName();
421 SchemaPath newSchemaPath = createSchemaPath(parentSchemaPath, nodeQName, nodeTypeQName);
423 if (nodeType instanceof BinaryTypeDefinition) {
424 BinaryTypeDefinition binType = (BinaryTypeDefinition) nodeType;
426 // List<Byte> bytes = (List<Byte>) binType.getDefaultValue();
427 // workaround to get rid of 'Unchecked cast' warning
428 List<Byte> bytes = new ArrayList<Byte>();
429 Object defaultValue = binType.getDefaultValue();
430 if (defaultValue instanceof List) {
431 for (Object o : List.class.cast(defaultValue)) {
432 if (o instanceof Byte) {
437 result = new BinaryType(newSchemaPath, bytes);
438 } else if (nodeType instanceof BitsTypeDefinition) {
439 BitsTypeDefinition bitsType = (BitsTypeDefinition) nodeType;
440 result = new BitsType(newSchemaPath, bitsType.getBits());
441 } else if (nodeType instanceof BooleanTypeDefinition) {
442 result = new BooleanType(newSchemaPath);
443 } else if (nodeType instanceof DecimalTypeDefinition) {
444 DecimalTypeDefinition decimalType = (DecimalTypeDefinition) nodeType;
445 result = new Decimal64(newSchemaPath, decimalType.getFractionDigits());
446 } else if (nodeType instanceof EmptyTypeDefinition) {
447 result = new EmptyType(newSchemaPath);
448 } else if (nodeType instanceof EnumTypeDefinition) {
449 EnumTypeDefinition enumType = (EnumTypeDefinition) nodeType;
450 result = new EnumerationType(newSchemaPath, (EnumPair) enumType.getDefaultValue(), enumType.getValues());
451 } else if (nodeType instanceof IdentityrefTypeDefinition) {
452 IdentityrefTypeDefinition idrefType = (IdentityrefTypeDefinition) nodeType;
453 result = new IdentityrefType(idrefType.getIdentity(), newSchemaPath);
454 } else if (nodeType instanceof InstanceIdentifierTypeDefinition) {
455 InstanceIdentifierTypeDefinition instIdType = (InstanceIdentifierTypeDefinition) nodeType;
456 return new InstanceIdentifier(newSchemaPath, instIdType.getPathStatement(),
457 instIdType.requireInstance());
458 } else if (nodeType instanceof StringTypeDefinition) {
459 result = TypeUtils.createNewStringType(parentSchemaPath, nodeQName, (StringTypeDefinition) nodeType);
460 } else if (nodeType instanceof IntegerTypeDefinition) {
461 result = TypeUtils.createNewIntType(parentSchemaPath, nodeQName, (IntegerTypeDefinition) nodeType);
462 } else if (nodeType instanceof UnsignedIntegerTypeDefinition) {
463 result = TypeUtils.createNewUintType(parentSchemaPath, nodeQName,
464 (UnsignedIntegerTypeDefinition) nodeType);
465 } else if (nodeType instanceof LeafrefTypeDefinition) {
466 result = new Leafref(newSchemaPath, ((LeafrefTypeDefinition) nodeType).getPathStatement());
467 } else if (nodeType instanceof UnionTypeDefinition) {
468 UnionTypeDefinition unionType = (UnionTypeDefinition) nodeType;
469 return new UnionType(newSchemaPath, unionType.getTypes());
470 } else if (nodeType instanceof ExtendedType) {
471 ExtendedType extType = (ExtendedType) nodeType;
472 result = TypeUtils.createNewExtendedType(extType, newSchemaPath);
479 * Create LeafSchemaNodeBuilder from given LeafSchemaNode.
482 * leaf from which to create builder
485 * current module name
488 * @return leaf builder based on given leaf node
490 public static LeafSchemaNodeBuilder createLeafBuilder(LeafSchemaNode leaf, QName qname, String moduleName, int line) {
491 final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(moduleName, line, qname, leaf.getPath());
492 convertDataSchemaNode(leaf, builder);
493 builder.setConfiguration(leaf.isConfiguration());
494 final TypeDefinition<?> type = leaf.getType();
495 builder.setType(type);
496 builder.setPath(leaf.getPath());
497 builder.setUnknownNodes(leaf.getUnknownSchemaNodes());
498 builder.setDefaultStr(leaf.getDefault());
499 builder.setUnits(leaf.getUnits());
504 * Create ContainerSchemaNodeBuilder from given ContainerSchemaNode.
509 * current module name
511 * current line in module
512 * @return container builder based on given container node
514 public static ContainerSchemaNodeBuilder createContainer(ContainerSchemaNode container, QName qname,
515 String moduleName, int line) {
516 final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(moduleName, line, qname,
517 container.getPath());
518 convertDataSchemaNode(container, builder);
519 builder.setConfiguration(container.isConfiguration());
520 builder.setUnknownNodes(container.getUnknownSchemaNodes());
521 builder.setChildNodes(container.getChildNodes());
522 builder.setGroupings(container.getGroupings());
523 builder.setTypedefs(container.getTypeDefinitions());
524 builder.setAugmentations(container.getAvailableAugmentations());
525 builder.setUsesnodes(container.getUses());
526 builder.setPresence(container.isPresenceContainer());
531 * Create ListSchemaNodeBuilder from given ListSchemaNode.
536 * current module name
538 * current line in module
539 * @return list builder based on given list node
541 public static ListSchemaNodeBuilder createList(ListSchemaNode list, QName qname, String moduleName, int line) {
542 ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(moduleName, line, qname, list.getPath());
543 convertDataSchemaNode(list, builder);
544 builder.setConfiguration(list.isConfiguration());
545 builder.setUnknownNodes(list.getUnknownSchemaNodes());
546 builder.setTypedefs(list.getTypeDefinitions());
547 builder.setChildNodes(list.getChildNodes());
548 builder.setGroupings(list.getGroupings());
549 builder.setAugmentations(list.getAvailableAugmentations());
550 builder.setUsesnodes(list.getUses());
551 builder.setUserOrdered(builder.isUserOrdered());
556 * Create LeafListSchemaNodeBuilder from given LeafListSchemaNode.
561 * current module name
563 * current line in module
564 * @return leaf-list builder based on given leaf-list node
566 public static LeafListSchemaNodeBuilder createLeafList(LeafListSchemaNode leafList, QName qname, String moduleName,
568 final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(moduleName, line, qname,
570 convertDataSchemaNode(leafList, builder);
571 builder.setConfiguration(leafList.isConfiguration());
572 builder.setType(leafList.getType());
573 builder.setUnknownNodes(leafList.getUnknownSchemaNodes());
574 builder.setUserOrdered(leafList.isUserOrdered());
579 * Create ChoiceBuilder from given ChoiceNode.
584 * current module name
586 * current line in module
587 * @return choice builder based on given choice node
589 public static ChoiceBuilder createChoice(ChoiceNode choice, QName qname, String moduleName, int line) {
590 final ChoiceBuilder builder = new ChoiceBuilder(moduleName, line, qname);
591 convertDataSchemaNode(choice, builder);
592 builder.setConfiguration(choice.isConfiguration());
593 builder.setCases(choice.getCases());
594 builder.setUnknownNodes(choice.getUnknownSchemaNodes());
595 builder.setDefaultCase(choice.getDefaultCase());
600 * Create AnyXmlBuilder from given AnyXmlSchemaNode.
605 * current module name
607 * current line in module
608 * @return anyxml builder based on given anyxml node
610 public static AnyXmlBuilder createAnyXml(AnyXmlSchemaNode anyxml, QName qname, String moduleName, int line) {
611 final AnyXmlBuilder builder = new AnyXmlBuilder(moduleName, line, qname, anyxml.getPath());
612 convertDataSchemaNode(anyxml, builder);
613 builder.setConfiguration(anyxml.isConfiguration());
614 builder.setUnknownNodes(anyxml.getUnknownSchemaNodes());
619 * Create GroupingBuilder from given GroupingDefinition.
624 * current module name
626 * current line in module
627 * @return grouping builder based on given grouping node
629 public static GroupingBuilder createGrouping(GroupingDefinition grouping, QName qname, String moduleName, int line) {
630 final GroupingBuilderImpl builder = new GroupingBuilderImpl(moduleName, line, qname);
631 builder.setPath(grouping.getPath());
632 builder.setChildNodes(grouping.getChildNodes());
633 builder.setGroupings(grouping.getGroupings());
634 builder.setTypedefs(grouping.getTypeDefinitions());
635 builder.setUsesnodes(grouping.getUses());
636 builder.setUnknownNodes(grouping.getUnknownSchemaNodes());
637 builder.setDescription(grouping.getDescription());
638 builder.setReference(grouping.getReference());
639 builder.setStatus(grouping.getStatus());
644 * Create TypeDefinitionBuilder from given ExtendedType.
649 * current module name
651 * current line in module
652 * @return typedef builder based on given typedef node
654 public static TypeDefinitionBuilder createTypedef(ExtendedType typedef, QName qname, String moduleName, int line) {
655 final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(moduleName, line, qname);
656 builder.setPath(typedef.getPath());
657 builder.setDefaultValue(typedef.getDefaultValue());
658 builder.setUnits(typedef.getUnits());
659 builder.setDescription(typedef.getDescription());
660 builder.setReference(typedef.getReference());
661 builder.setStatus(typedef.getStatus());
662 builder.setRanges(typedef.getRanges());
663 builder.setLengths(typedef.getLengths());
664 builder.setPatterns(typedef.getPatterns());
665 builder.setFractionDigits(typedef.getFractionDigits());
666 final TypeDefinition<?> type = typedef.getBaseType();
667 builder.setType(type);
668 builder.setUnits(typedef.getUnits());
669 builder.setUnknownNodes(typedef.getUnknownSchemaNodes());
674 * Create UnknownSchemaNodeBuilder from given UnknownSchemaNode.
679 * current module name
681 * current line in module
682 * @return unknown node builder based on given unknown node
684 public static UnknownSchemaNodeBuilder createUnknownSchemaNode(UnknownSchemaNode unknownNode, QName qname,
685 String moduleName, int line) {
686 final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(moduleName, line, qname);
687 builder.setPath(unknownNode.getPath());
688 builder.setUnknownNodes(unknownNode.getUnknownSchemaNodes());
689 builder.setDescription(unknownNode.getDescription());
690 builder.setReference(unknownNode.getReference());
691 builder.setStatus(unknownNode.getStatus());
692 builder.setAddedByUses(unknownNode.isAddedByUses());
693 builder.setNodeType(unknownNode.getNodeType());
694 builder.setNodeParameter(unknownNode.getNodeParameter());
699 * Set DataSchemaNode arguments to builder object
702 * node from which arguments should be read
704 * builder to which arguments should be set
706 private static void convertDataSchemaNode(DataSchemaNode node, DataSchemaNodeBuilder builder) {
707 builder.setPath(node.getPath());
708 builder.setDescription(node.getDescription());
709 builder.setReference(node.getReference());
710 builder.setStatus(node.getStatus());
711 builder.setAugmenting(node.isAugmenting());
712 copyConstraintsFromDefinition(node.getConstraints(), builder.getConstraints());
716 * Copy constraints from constraints definition to constraints builder.
718 * @param nodeConstraints
719 * definition from which constraints will be copied
721 * builder to which constraints will be added
723 private static void copyConstraintsFromDefinition(final ConstraintDefinition nodeConstraints,
724 final ConstraintsBuilder constraints) {
725 final RevisionAwareXPath when = nodeConstraints.getWhenCondition();
726 final Set<MustDefinition> must = nodeConstraints.getMustConstraints();
729 constraints.addWhenCondition(when.toString());
732 for (MustDefinition md : must) {
733 constraints.addMustDefinition(md);
736 constraints.setMandatory(nodeConstraints.isMandatory());
737 constraints.setMinElements(nodeConstraints.getMinElements());
738 constraints.setMaxElements(nodeConstraints.getMaxElements());
742 * Find augment target node and perform augmentation.
745 * @param firstNodeParent
746 * parent of first node in path
748 * path to augment target
749 * @param isUsesAugment
750 * if this augment is defined under uses node
751 * @return true if augment process succeed, false otherwise
753 public static boolean processAugmentation(final AugmentationSchemaBuilder augment, final Builder firstNodeParent,
754 final List<QName> path, boolean isUsesAugment) {
755 // traverse augment target path and try to reach target node
756 String currentName = null;
757 Builder currentParent = firstNodeParent;
759 for (int i = 0; i < path.size(); i++) {
760 QName qname = path.get(i);
762 currentName = qname.getLocalName();
763 if (currentParent instanceof DataNodeContainerBuilder) {
764 DataSchemaNodeBuilder nodeFound = ((DataNodeContainerBuilder) currentParent)
765 .getDataChildByName(currentName);
766 // if not found as regular child, search in uses
767 if (nodeFound == null) {
768 boolean found = false;
769 for (UsesNodeBuilder unb : ((DataNodeContainerBuilder) currentParent).getUsesNodes()) {
770 DataSchemaNodeBuilder result = findNodeInUses(currentName, unb);
771 if (result != null) {
772 currentParent = result;
777 // if not found even in uses nodes, return false
782 currentParent = nodeFound;
784 } else if (currentParent instanceof ChoiceBuilder) {
785 currentParent = ((ChoiceBuilder) currentParent).getCaseNodeByName(currentName);
787 throw new YangParseException(augment.getModuleName(), augment.getLine(),
788 "Error in augment parsing: failed to find node " + currentName);
791 // if node in path not found, return false
792 if (currentParent == null) {
796 if (!(currentParent instanceof DataSchemaNodeBuilder)) {
797 throw new YangParseException(
798 augment.getModuleName(),
800 "Error in augment parsing: The target node MUST be either a container, list, choice, case, input, output, or notification node.");
803 if (currentParent instanceof ChoiceBuilder) {
804 fillAugmentTarget(augment, (ChoiceBuilder) currentParent);
806 fillAugmentTarget(augment, (DataNodeContainerBuilder) currentParent);
808 ((AugmentationTargetBuilder) currentParent).addAugmentation(augment);
809 SchemaPath oldPath = ((DataSchemaNodeBuilder) currentParent).getPath();
810 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
811 augment.setResolved(true);
816 private static DataSchemaNodeBuilder findNodeInUses(String localName, UsesNodeBuilder uses) {
817 Set<DataSchemaNodeBuilder> usesTargetChildren = uses.getTargetChildren();
818 if (usesTargetChildren != null) {
819 for (DataSchemaNodeBuilder child : uses.getTargetChildren()) {
820 if (child.getQName().getLocalName().equals(localName)) {
825 for (UsesNodeBuilder usesNode : uses.getTargetGroupingUses()) {
826 DataSchemaNodeBuilder result = findNodeInUses(localName, usesNode);
827 if (result != null) {
835 * Find augment target node in given context and perform augmentation.
839 * path to augment target
843 * current prefix of target module
845 * SchemaContext containing already resolved modules
846 * @return true if augment process succeed, false otherwise
848 public static boolean processAugmentationOnContext(final AugmentationSchemaBuilder augment, final List<QName> path,
849 final ModuleBuilder module, final String prefix, final SchemaContext context) {
850 final int line = augment.getLine();
851 final Module dependentModule = findModuleFromContext(context, module, prefix, line);
852 if (dependentModule == null) {
853 throw new YangParseException(module.getName(), line,
854 "Error in augment parsing: failed to find module with prefix " + prefix + ".");
857 String currentName = path.get(0).getLocalName();
858 SchemaNode currentParent = dependentModule.getDataChildByName(currentName);
859 if (currentParent == null) {
860 Set<NotificationDefinition> notifications = dependentModule.getNotifications();
861 for (NotificationDefinition ntf : notifications) {
862 if (ntf.getQName().getLocalName().equals(currentName)) {
868 if (currentParent == null) {
869 throw new YangParseException(module.getName(), line, "Error in augment parsing: failed to find node "
870 + currentName + ".");
873 for (int i = 1; i < path.size(); i++) {
874 currentName = path.get(i).getLocalName();
875 if (currentParent instanceof DataNodeContainer) {
876 currentParent = ((DataNodeContainer) currentParent).getDataChildByName(currentName);
877 } else if (currentParent instanceof ChoiceNode) {
878 currentParent = ((ChoiceNode) currentParent).getCaseNodeByName(currentName);
880 throw new YangParseException(augment.getModuleName(), line,
881 "Error in augment parsing: failed to find node " + currentName);
883 // if node in path not found, return false
884 if (currentParent == null) {
885 throw new YangParseException(module.getName(), line, "Error in augment parsing: failed to find node "
886 + currentName + ".");
890 if (currentParent instanceof ContainerSchemaNodeImpl) {
891 // includes container, input and output statement
892 ContainerSchemaNodeImpl c = (ContainerSchemaNodeImpl) currentParent;
893 ContainerSchemaNodeBuilder cb = c.toBuilder();
894 fillAugmentTarget(augment, cb);
895 ((AugmentationTargetBuilder) cb).addAugmentation(augment);
896 SchemaPath oldPath = cb.getPath();
898 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
899 augment.setResolved(true);
900 } else if (currentParent instanceof ListSchemaNodeImpl) {
901 ListSchemaNodeImpl l = (ListSchemaNodeImpl) currentParent;
902 ListSchemaNodeBuilder lb = l.toBuilder();
903 fillAugmentTarget(augment, lb);
904 ((AugmentationTargetBuilder) lb).addAugmentation(augment);
905 SchemaPath oldPath = lb.getPath();
907 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
908 augment.setResolved(true);
909 } else if (currentParent instanceof ChoiceNodeImpl) {
910 ChoiceNodeImpl ch = (ChoiceNodeImpl) currentParent;
911 ChoiceBuilder chb = ch.toBuilder();
912 fillAugmentTarget(augment, chb);
913 ((AugmentationTargetBuilder) chb).addAugmentation(augment);
914 SchemaPath oldPath = chb.getPath();
916 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
917 augment.setResolved(true);
918 } else if (currentParent instanceof ChoiceCaseNodeImpl) {
919 ChoiceCaseNodeImpl chc = (ChoiceCaseNodeImpl) currentParent;
920 ChoiceCaseBuilder chcb = chc.toBuilder();
921 fillAugmentTarget(augment, chcb);
922 ((AugmentationTargetBuilder) chcb).addAugmentation(augment);
923 SchemaPath oldPath = chcb.getPath();
925 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
926 augment.setResolved(true);
927 } else if (currentParent instanceof NotificationDefinitionImpl) {
928 NotificationDefinitionImpl nd = (NotificationDefinitionImpl) currentParent;
929 NotificationBuilder nb = nd.toBuilder();
930 fillAugmentTarget(augment, nb);
931 ((AugmentationTargetBuilder) nb).addAugmentation(augment);
932 SchemaPath oldPath = nb.getPath();
934 augment.setTargetPath(new SchemaPath(oldPath.getPath(), oldPath.isAbsolute()));
935 augment.setResolved(true);
937 throw new YangParseException(module.getName(), line, "Target of type " + currentParent.getClass()
938 + " cannot be augmented.");
944 public static QName findFullQName(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
945 final ModuleBuilder module, final IdentityrefTypeBuilder idref) {
947 String baseString = idref.getBaseString();
948 if (baseString.contains(":")) {
949 String[] splittedBase = baseString.split(":");
950 if (splittedBase.length > 2) {
951 throw new YangParseException(module.getName(), idref.getLine(), "Failed to parse identityref base: "
954 String prefix = splittedBase[0];
955 String name = splittedBase[1];
956 ModuleBuilder dependentModule = findDependentModuleBuilder(modules, module, prefix, idref.getLine());
957 result = new QName(dependentModule.getNamespace(), dependentModule.getRevision(), prefix, name);
959 result = new QName(module.getNamespace(), module.getRevision(), module.getPrefix(), baseString);
965 * Load uses target nodes and all uses target uses target nodes. Set this
966 * collection as uses final children.
972 public static void processUsesNode(final UsesNodeBuilder usesNode) {
973 ModuleBuilder module = getParentModule(usesNode);
974 DataNodeContainerBuilder parent = usesNode.getParent();
975 URI namespace = null;
976 Date revision = null;
977 String prefix = null;
978 if (parent instanceof ModuleBuilder || parent instanceof AugmentationSchemaBuilder) {
979 namespace = module.getNamespace();
980 revision = module.getRevision();
981 prefix = module.getPrefix();
983 QName parentQName = parent.getQName();
984 namespace = parentQName.getNamespace();
985 revision = parentQName.getRevision();
986 prefix = parentQName.getPrefix();
988 SchemaPath parentPath = parent.getPath();
991 Set<DataSchemaNodeBuilder> finalChildren = new HashSet<>();
992 Set<DataSchemaNodeBuilder> newChildren = GroupingUtils.copyUsesTargetNodesWithNewPath(usesNode, parent);
993 finalChildren.addAll(newChildren);
994 usesNode.getFinalChildren().addAll(finalChildren);
997 Set<GroupingBuilder> finalGroupings = new HashSet<>();
998 Set<GroupingBuilder> newGroupings = GroupingUtils.copyUsesTargetGroupingsWithNewPath(usesNode, parentPath,
999 namespace, revision, prefix);
1000 finalGroupings.addAll(newGroupings);
1001 usesNode.getFinalGroupings().addAll(finalGroupings);
1004 Set<TypeDefinitionBuilder> finalTypedefs = new HashSet<>();
1005 Set<TypeDefinitionBuilder> newTypedefs = GroupingUtils.copyUsesTargetTypedefsWithNewPath(usesNode, parentPath,
1006 namespace, revision, prefix);
1007 finalTypedefs.addAll(newTypedefs);
1008 usesNode.getFinalTypedefs().addAll(finalTypedefs);
1011 List<UnknownSchemaNodeBuilder> finalUnknownNodes = new ArrayList<>();
1012 List<UnknownSchemaNodeBuilder> newUnknownNodes = GroupingUtils.copyUsesTargetUnknownNodesWithNewPath(usesNode,
1013 parentPath, namespace, revision, prefix);
1014 finalUnknownNodes.addAll(newUnknownNodes);
1015 usesNode.getFinalUnknownNodes().addAll(finalUnknownNodes);
1019 * Add nodes defined in uses target grouping to uses parent.
1023 public static void updateUsesParent(UsesNodeBuilder usesNode, DataNodeContainerBuilder parent) {
1025 for (DataSchemaNodeBuilder child : usesNode.getFinalChildren()) {
1026 child.setParent(parent);
1027 parent.addChildNode(child);
1029 for (UsesNodeBuilder uses : usesNode.getTargetGroupingUses()) {
1030 updateUsesParent(uses, parent);
1034 for (GroupingBuilder gb : usesNode.getFinalGroupings()) {
1035 parent.addGrouping(gb);
1038 for (TypeDefinitionBuilder tdb : usesNode.getFinalTypedefs()) {
1039 parent.addTypedef(tdb);
1042 for (UnknownSchemaNodeBuilder un : usesNode.getFinalUnknownNodes()) {
1043 parent.addUnknownNodeBuilder(un);
1047 public static void fixUsesNodesPath(UsesNodeBuilder usesNode) {
1048 DataNodeContainerBuilder parent = usesNode.getParent();
1051 Set<DataSchemaNodeBuilder> currentChildNodes = parent.getChildNodeBuilders();
1052 Set<DataSchemaNodeBuilder> toRemove = new HashSet<>();
1053 Set<DataSchemaNodeBuilder> toAdd = new HashSet<>();
1054 for (DataSchemaNodeBuilder child : currentChildNodes) {
1055 if (child instanceof GroupingMember) {
1056 GroupingMember gm = (GroupingMember) child;
1057 if (gm.isAddedByUses()) {
1058 toRemove.add(child);
1059 DataSchemaNodeBuilder copy = CopyUtils.copy(child, parent, true);
1060 correctNodePath(copy, parent.getPath());
1065 currentChildNodes.removeAll(toRemove);
1066 currentChildNodes.addAll(toAdd);
1069 Set<GroupingBuilder> currentGroupings = parent.getGroupingBuilders();
1070 Set<GroupingBuilder> toRemoveG = new HashSet<>();
1071 Set<GroupingBuilder> toAddG = new HashSet<>();
1072 for (GroupingBuilder child : currentGroupings) {
1073 if (child.isAddedByUses()) {
1074 toRemoveG.add(child);
1075 GroupingBuilder copy = CopyUtils.copy(child, parent, true);
1076 correctNodePath(copy, parent.getPath());
1081 currentGroupings.removeAll(toRemoveG);
1082 currentGroupings.addAll(toAddG);
1085 Set<TypeDefinitionBuilder> currentTypedefs = parent.getTypeDefinitionBuilders();
1086 Set<TypeDefinitionBuilder> toRemoveTD = new HashSet<>();
1087 Set<TypeDefinitionBuilder> toAddTD = new HashSet<>();
1088 for (TypeDefinitionBuilder child : currentTypedefs) {
1089 if (child.isAddedByUses()) {
1090 toRemoveTD.add(child);
1091 TypeDefinitionBuilder copy = CopyUtils.copy(child, parent, true);
1092 correctNodePath(copy, parent.getPath());
1097 currentTypedefs.removeAll(toRemoveTD);
1098 currentTypedefs.addAll(toAddTD);
1101 List<UnknownSchemaNodeBuilder> currentUN = parent.getUnknownNodeBuilders();
1102 List<UnknownSchemaNodeBuilder> toRemoveUN = new ArrayList<>();
1103 List<UnknownSchemaNodeBuilder> toAddUN = new ArrayList<>();
1104 for (UnknownSchemaNodeBuilder un : currentUN) {
1105 if (un.isAddedByUses()) {
1107 UnknownSchemaNodeBuilder copy = CopyUtils.copy(un, parent, true);
1108 correctNodePath(copy, parent.getPath());
1112 currentUN.removeAll(toRemoveUN);
1113 currentUN.addAll(toAddUN);
1117 * Perform refine process on uses children. It is expected that uses has
1118 * already resolved all dependencies.
1122 public static void performRefine(UsesNodeBuilder usesNode) {
1123 for (RefineHolder refine : usesNode.getRefines()) {
1124 DataSchemaNodeBuilder nodeToRefine = null;
1125 for (DataSchemaNodeBuilder dataNode : usesNode.getFinalChildren()) {
1126 if (refine.getName().equals(dataNode.getQName().getLocalName())) {
1127 nodeToRefine = dataNode;
1131 if (nodeToRefine == null) {
1132 throw new YangParseException(refine.getModuleName(), refine.getLine(), "Refine target node '"
1133 + refine.getName() + "' not found");
1135 RefineUtils.performRefine(nodeToRefine, refine);
1136 usesNode.addRefineNode(nodeToRefine);
1141 * Get module in which this node is defined.
1144 * @return builder of module where this node is defined
1146 public static ModuleBuilder getParentModule(Builder node) {
1147 Builder parent = node.getParent();
1148 while (!(parent instanceof ModuleBuilder)) {
1149 parent = parent.getParent();
1151 return (ModuleBuilder) parent;