2 * Copyright (c) 2014 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.mdsal.unified.html.generator
10 import static java.util.Objects.requireNonNull
12 import java.util.ArrayList
13 import java.util.Collection
14 import java.util.HashMap
15 import java.util.HashSet
16 import java.util.LinkedHashMap
19 import java.util.Optional
21 import org.opendaylight.yangtools.yang.common.QName
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates
24 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode
25 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
26 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode
27 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode
28 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
29 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
31 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext
32 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraintAware
33 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
34 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
38 import org.opendaylight.yangtools.yang.model.api.MandatoryAware
39 import org.opendaylight.yangtools.yang.model.api.Module
40 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
41 import org.opendaylight.yangtools.yang.model.api.SchemaNode
42 import org.opendaylight.yangtools.yang.model.api.SchemaPath
43 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
44 import org.opendaylight.yangtools.yang.model.api.UsesNode
45 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier
46 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute
47 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
48 import org.opendaylight.yangtools.yang.model.api.type.LengthRestrictedTypeDefinition
49 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
50 import org.opendaylight.yangtools.yang.model.api.type.RangeRestrictedTypeDefinition
52 @Deprecated(forRemoval = true)
53 final class DocumentationTemplate {
54 val Map<String, String> imports = new HashMap
55 val Map<TypeDefinition<?>, SchemaPath> types
56 val EffectiveModelContext ctx
59 StringBuilder augmentChildNodesAsString
61 DataSchemaNode lastNodeInTargetPath = null
63 new(EffectiveModelContext context, Map<TypeDefinition<?>, SchemaPath> types, Module module) {
64 this.ctx = requireNonNull(context)
65 this.types = requireNonNull(types)
66 this.module = requireNonNull(module)
67 module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
74 <title>«module.name»</title>
79 «typeDefinitionsSummary»
82 «augmentationsSummary»
84 «notificationsSummary»
112 private def typeDefinitionsSummary() {
113 val Collection<? extends TypeDefinition<?>> typedefs = module.typeDefinitions
114 if (typedefs.empty) {
119 <h3>Type Definitions Summary</h3>
125 «FOR typedef : typedefs»
128 «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
131 «typedef.description»
140 private def typeDefinitions() {
141 val Collection<? extends TypeDefinition<?>> typedefs = module.typeDefinitions
142 if (typedefs.empty) {
146 <h2>Type Definitions</h2>
148 «FOR typedef : typedefs»
150 <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
152 «typedef.descAndRefLi»
153 «typedef.restrictions»
161 private def identities() {
162 if (module.identities.empty) {
168 «FOR identity : module.identities»
170 <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
172 «identity.descAndRefLi»
173 «IF !identity.baseIdentities.isEmpty»
174 «listItem("base", identity.baseIdentities.get(0).QName.localName)»
183 private def identitiesSummary() {
184 if (module.identities.empty) {
188 <h3>Identities Summary</h3>
194 «FOR identity : module.identities»
197 «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
200 «identity.description»
208 private def groupings() {
209 if (module.groupings.empty) {
215 «FOR grouping : module.groupings»
217 <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
219 «grouping.descAndRefLi»
220 «FOR childNode : grouping.childNodes»
221 «childNode.printSchemaNodeInfo»
230 private def groupingsSummary() {
231 if (module.groupings.empty) {
235 <h3>Groupings Summary</h3>
241 «FOR grouping : module.groupings»
244 «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
247 «grouping.description»
255 private def dataStore() {
256 if (module.childNodes.empty) {
260 <h2>Datastore Structure</h2>
265 private def augmentations() {
266 if (module.augmentations.empty) {
270 <h2>Augmentations</h2>
273 «FOR augment : module.augmentations»
275 <h3 id="«schemaPathToString(augment.targetPath, augment)»">
276 Target [«typeAnchorLink(augment.targetPath.asSchemaPath, schemaPathToString(augment.targetPath, augment))»]</h3>
277 «augment.description»
278 Status: «strong(String.valueOf(augment.status))»
279 «IF augment.reference !== null»
280 Reference «augment.reference»
282 «IF augment.whenCondition !== null»
283 When «augment.whenCondition.toString»
285 «FOR childNode : augment.childNodes»
286 «childNode.printSchemaNodeInfo»
290 «createAugmentChildNodesAsString(new ArrayList(augment.childNodes))»
291 «printNodeChildren(parseTargetPath(augment.targetPath))»
298 private def createAugmentChildNodesAsString(List<DataSchemaNode> childNodes) {
299 augmentChildNodesAsString = new StringBuilder();
300 augmentChildNodesAsString.append(printNodeChildren(childNodes))
304 private def parseTargetPath(SchemaNodeIdentifier path) {
305 val nodes = new ArrayList<DataSchemaNode>();
306 for (QName pathElement : path.nodeIdentifiers) {
307 val module = ctx.findModule(pathElement.module)
308 if (module.isPresent) {
309 var foundNode = module.get.dataChildByName(pathElement)
310 if (foundNode === null) {
311 val child = nodes.last
312 if (child instanceof DataNodeContainer) {
313 val dataContNode = child as DataNodeContainer
314 foundNode = findNodeInChildNodes(pathElement, dataContNode.childNodes)
317 if (foundNode !== null) {
318 nodes.add(foundNode);
323 lastNodeInTargetPath = nodes.get(nodes.size() - 1)
326 val targetPathNodes = new ArrayList<DataSchemaNode>();
327 targetPathNodes.add(lastNodeInTargetPath)
329 return targetPathNodes
332 private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable<? extends DataSchemaNode> childNodes) {
333 for (child : childNodes) {
334 if (child.QName.equals(findingNode))
338 for(child : childNodes) {
339 if (child instanceof ContainerSchemaNode) {
340 val foundChild = findNodeInChildNodes(findingNode, child.childNodes)
341 if (foundChild !== null)
343 } else if (child instanceof ListSchemaNode) {
344 val foundChild = findNodeInChildNodes(findingNode, child.childNodes)
345 if (foundChild !== null)
351 private def printNodeChildren(List<DataSchemaNode> childNodes) {
352 if (childNodes.empty) {
359 «printAugmentedNode(childNodes.get(0))»
364 private def CharSequence printAugmentedNode(DataSchemaNode child) {
366 if(child instanceof CaseSchemaNode)
371 «IF child instanceof ContainerSchemaNode»
372 «printContainerNode(child)»
374 «IF child instanceof AnyxmlSchemaNode»
375 «printAnyXmlNode(child)»
377 «IF child instanceof LeafSchemaNode»
378 «printLeafNode(child)»
380 «IF child instanceof LeafListSchemaNode»
381 «printLeafListNode(child)»
383 «IF child instanceof ListSchemaNode»
384 «printListNode(child)»
386 «IF child instanceof ChoiceSchemaNode»
387 «printChoiceNode(child)»
392 private def printChoiceNode(ChoiceSchemaNode child) {
393 val cases = new ArrayList(child.cases)
395 val CaseSchemaNode aCase = cases.get(0)
396 for (caseChildNode : aCase.childNodes)
397 printAugmentedNode(caseChildNode)
401 private def printListNode(ListSchemaNode listNode) {
404 <«listNode.QName.localName»«IF !listNode.QName.namespace.equals(module.namespace)» xmlns="«listNode.QName.namespace»"«ENDIF»>
405 «FOR child : listNode.childNodes»
406 «printAugmentedNode(child)»
408 </«listNode.QName.localName»>
412 private def printContainerNode(ContainerSchemaNode containerNode) {
415 <«containerNode.QName.localName»«IF !containerNode.QName.namespace.equals(module.namespace)» xmlns="«containerNode.QName.namespace»"«ENDIF»>
416 «FOR child : containerNode.childNodes»
417 «printAugmentedNode(child)»
419 </«containerNode.QName.localName»>
423 private def printLeafListNode(LeafListSchemaNode leafListNode) {
426 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
427 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
428 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
432 private def printAnyXmlNode(AnyxmlSchemaNode anyXmlNode) {
435 <«anyXmlNode.QName.localName»>. . .</«anyXmlNode.QName.localName»>
439 private def printLeafNode(LeafSchemaNode leafNode) {
442 <«leafNode.QName.localName»>. . .</«leafNode.QName.localName»>
446 private def augmentationsSummary() {
447 if (module.augmentations.empty) {
451 <h3>Augmentations Summary</h3>
457 «FOR augment : module.augmentations»
460 «anchorLink(schemaPathToString(augment.targetPath, augment),
461 strong(schemaPathToString(augment.targetPath, augment)))»
464 «augment.description»
472 private def notifications() {
473 val Collection<? extends NotificationDefinition> notificationdefs = module.notifications
474 if (notificationdefs.empty) {
479 <h2>Notifications</h2>
480 «FOR notificationdef : notificationdefs»
482 <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
483 «notificationdef.descAndRef»
484 «FOR childNode : notificationdef.childNodes»
485 «childNode.printSchemaNodeInfo»
491 private def notificationsSummary() {
492 if (module.notifications.empty) {
496 <h3>Notifications Summary</h3>
502 «FOR notification : module.notifications»
505 «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
508 «notification.description»
517 if (module.rpcs.empty) {
522 <h2>RPC Definitions</h2>
523 «FOR rpc : module.rpcs»
524 <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
527 «rpc.input.printSchemaNodeInfo»
528 «rpc.output.printSchemaNodeInfo»
535 private def rpcsSummary() {
536 if (module.rpcs.empty) {
540 <h3>RPCs Summary</h3>
546 «FOR rpc : module.rpcs»
549 «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
560 private def extensions() {
561 if (module.extensionSchemaNodes.empty) {
566 «FOR ext : module.extensionSchemaNodes»
568 <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
575 private def extensionsSummary() {
576 if (module.extensionSchemaNodes.empty) {
580 <h3>Extensions Summary</h3>
586 «FOR ext : module.extensionSchemaNodes»
589 «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
600 private def features() {
601 if (module.features.empty) {
608 «FOR feature : module.features»
610 <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
612 «feature.descAndRefLi»
620 private def featuresSummary() {
621 if (module.features.empty) {
625 <h3>Features Summary</h3>
631 «FOR feature : module.features»
634 «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
637 «feature.description»
645 private def objectsSummary() {
646 if (module.childNodes.empty) {
650 <h3>Child Nodes Summary</h3>
656 «FOR childNode : module.childNodes»
659 «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
662 «childNode.description»
670 private def header() '''
671 <h1>«module.name»</h1>
673 <h2>Base Information</h2>
676 <td>«strong("prefix")»</td>
677 <td>«module.prefix»</td>
680 <td>«strong("namespace")»</td>
681 <td>«module.namespace»</td>
684 «IF module.revision.isPresent»
685 <td>«strong("revision")»</td>
686 <td>«module.revision.get.toString»</td>
690 <td>«strong("description")»</td>
691 <td>«module.description»</td>
694 <td>«strong("yang-version")»</td>
695 <td>«module.yangVersion»</td>
698 «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
699 «imp.prefix»:«imp.moduleName»«IF imp.revision.isPresent» «imp.revision.get.toString»«ENDIF»;
705 def CharSequence schemaPathToId(SchemaPath path) {
707 return '''«FOR qName : path.pathFromRoot SEPARATOR "/"»«qName.localName»«ENDFOR»'''
711 def code(String string) '''<code>«string»</code>'''
713 def process(Module module) {
714 throw new UnsupportedOperationException("TODO: auto-generated method stub")
717 def CharSequence tree(Module module) '''
718 «strong(module.name)»
719 «module.childNodes.treeSet(YangInstanceIdentifier.builder.build())»
722 private def CharSequence tree(ChoiceSchemaNode node, YangInstanceIdentifier path) '''
723 «node.nodeName» (choice)
724 «casesTree(node.cases, path)»
727 def casesTree(Collection<? extends CaseSchemaNode> nodes, YangInstanceIdentifier path) '''
732 «node.childNodes.treeSet(path)»
738 private def CharSequence tree(DataSchemaNode node, YangInstanceIdentifier path) {
739 if (node instanceof ChoiceSchemaNode) {
740 return tree(node, path)
741 } else if (node instanceof ListSchemaNode) {
742 return tree(node, path)
743 } else if (node instanceof ContainerSchemaNode) {
744 return tree(node, path)
749 private def CharSequence tree(ListSchemaNode node, YangInstanceIdentifier path) '''
750 «val newPath = path.append(node)»
751 «localLink(newPath,node.nodeName)»
752 «node.childNodes.treeSet(newPath)»
755 private def CharSequence tree(ContainerSchemaNode node,YangInstanceIdentifier path) '''
756 «val newPath = path.append(node)»
757 «localLink(newPath,node.nodeName)»
758 «node.childNodes.treeSet(newPath)»
761 private def CharSequence childNodes() '''
762 «val childNodes = module.childNodes»
763 «IF !childNodes.nullOrEmpty»
766 «childNodes.printChildren(3,YangInstanceIdentifier.builder().build())»
770 def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
774 «IF node instanceof DataNodeContainer»
775 «val dataNode = node as DataNodeContainer»
777 «FOR usesNode : dataNode.uses»
782 «FOR typeDef : dataNode.typeDefinitions»
783 «typeDef.restrictions»
787 «FOR grouping : dataNode.groupings»
788 «grouping.printGrouping»
792 «FOR child : dataNode.childNodes»
793 «child.printSchemaNodeInfo»
801 def String typeAnchorLink(SchemaPath path, CharSequence text) {
803 val lastElement = path.lastComponent
804 val ns = lastElement.namespace
805 if (ns.equals(module.namespace)) {
806 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
808 return '''(«ns»)«text»'''
809 //to enable external (import) links
810 //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
815 def CharSequence printBaseInfo(SchemaNode node) {
816 if(node instanceof LeafSchemaNode) {
818 «printInfo(node, "leaf")»
819 «listItem("type", typeAnchorLink(types.get(node.type), node.type.QName.localName))»
820 «listItem("units", node.type.units.orElse(null))»
821 «listItem("default", node.type.defaultValue.map([ Object o | o.toString]).orElse(null))»
824 } else if(node instanceof LeafListSchemaNode) {
826 «printInfo(node, "leaf-list")»
827 «IF node.type !== null»
828 «listItem("type", node.type.QName.localName)»
832 } else if(node instanceof ListSchemaNode) {
834 «printInfo(node, "list")»
835 «FOR keyDef : node.keyDefinition»
836 «listItem("key definition", keyDef.localName)»
840 } else if(node instanceof ChoiceSchemaNode) {
842 «printInfo(node, "choice")»
843 «listItem("default case", node.defaultCase.map([ CaseSchemaNode n | n.getQName.localName]).orElse(null))»
844 «FOR caseNode : node.cases»
845 «caseNode.printSchemaNodeInfo»
849 } else if(node instanceof CaseSchemaNode) {
851 «printInfo(node, "case")»
854 } else if(node instanceof ContainerSchemaNode) {
856 «printInfo(node, "container")»
859 } else if(node instanceof AnyxmlSchemaNode) {
861 «printInfo(node, "anyxml")»
867 def CharSequence printInfo(SchemaNode node, String nodeType) {
869 «IF node instanceof AugmentationTarget»
872 <li id="«node.path.schemaPathToId»">
873 «nodeType»: «node.QName.localName»
878 «strong(listItem(nodeType, node.QName.localName))»
881 «listItem("description", node.description.orElse(null))»
882 «listItem("reference", node.reference.orElse(null))»
883 «IF node instanceof DataSchemaNode»
884 «IF node.whenCondition.present»
885 «listItem("when condition", node.whenCondition.get.toString)»
888 «IF node instanceof ElementCountConstraintAware»
889 «IF node.elementCountConstraint.present»
890 «val constraint = node.elementCountConstraint.get»
891 «listItem("min elements", constraint.minElements?.toString)»
892 «listItem("max elements", constraint.maxElements?.toString)»
898 def CharSequence printUses(UsesNode usesNode) {
900 «strong(listItem("uses", typeAnchorLink(usesNode.sourceGrouping.path, usesNode.sourceGrouping.QName.localName)))»
904 «FOR sp : usesNode.refines.keySet»
905 «listItem("node name", usesNode.refines.get(sp).QName.localName)»
909 «FOR augment : usesNode.augmentations»
910 «typeAnchorLink(augment.targetPath.asSchemaPath, schemaPathToString(augment.targetPath, augment))»
916 def CharSequence printGrouping(GroupingDefinition grouping) {
918 «strong(listItem("grouping", grouping.QName.localName))»
922 def CharSequence printChildren(Iterable<? extends DataSchemaNode> nodes, int level, YangInstanceIdentifier path) {
923 val anyxmlNodes = nodes.filter(AnyxmlSchemaNode)
924 val leafNodes = nodes.filter(LeafSchemaNode)
925 val leafListNodes = nodes.filter(LeafListSchemaNode)
926 val choices = nodes.filter(ChoiceSchemaNode)
927 val cases = nodes.filter(CaseSchemaNode)
928 val containers = nodes.filter(ContainerSchemaNode)
929 val lists = nodes.filter(ListSchemaNode)
931 «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
932 <h3>Direct children</h3>
934 «FOR childNode : anyxmlNodes»
935 «childNode.printShortInfo(level,path)»
937 «FOR childNode : leafNodes»
938 «childNode.printShortInfo(level,path)»
940 «FOR childNode : leafListNodes»
941 «childNode.printShortInfo(level,path)»
943 «FOR childNode : containers»
944 «childNode.printShortInfo(level,path)»
946 «FOR childNode : lists»
947 «childNode.printShortInfo(level,path)»
952 «IF path.pathArguments.iterator.hasNext»
954 «nodes.xmlExample(path.pathArguments.last.nodeType,path)»
957 «FOR childNode : containers»
958 «childNode.printInfo(level,path)»
960 «FOR childNode : lists»
961 «childNode.printInfo(level,path)»
963 «FOR childNode : choices»
964 «childNode.printInfo(level,path)»
966 «FOR childNode : cases»
967 «childNode.printInfo(level,path)»
972 def CharSequence xmlExample(Iterable<? extends DataSchemaNode> nodes, QName name, YangInstanceIdentifier path) '''
974 «xmlExampleTag(name,nodes.xmplExampleTags(path))»
978 def CharSequence xmplExampleTags(Iterable<? extends DataSchemaNode> nodes, YangInstanceIdentifier identifier) '''
981 <!-- «node.QName.localName» -->
982 «node.asXmlExampleTag(identifier)»
987 private def CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) {
988 if (node instanceof LeafSchemaNode) {
989 return '''«node.QName.xmlExampleTag("...")»'''
991 if (node instanceof LeafListSchemaNode) {
993 <!-- This node could appear multiple times -->
994 «node.QName.xmlExampleTag("...")»
997 if (node instanceof ContainerSchemaNode) {
999 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
1000 «node.QName.xmlExampleTag("...")»
1003 if (node instanceof ListSchemaNode) {
1005 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
1006 <!-- This node could appear multiple times -->
1007 «node.QName.xmlExampleTag("...")»
1010 return "<!-- noop -->"
1013 def xmlExampleTag(QName name, CharSequence data) {
1014 return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
1017 def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''
1020 def header(int level,YangInstanceIdentifier name) '''
1021 <h«level» id="«FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
1022 «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
1026 private def CharSequence printInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) '''
1027 «val newPath = path.append(node)»
1028 «header(level,newPath)»
1031 <dd>«newPath.asXmlPath»</dd>
1032 <dt>Restconf path</dt>
1033 <dd>«code(newPath.asRestconfPath)»</dd>
1035 «node.childNodes.printChildren(level,newPath)»
1038 private def CharSequence printInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) '''
1039 «val newPath = path.append(node)»
1040 «header(level,newPath)»
1043 <dd>«newPath.asXmlPath»</dd>
1044 <dt>Restconf path</dt>
1045 <dd>«code(newPath.asRestconfPath)»</dd>
1047 «node.childNodes.printChildren(level,newPath)»
1050 private def CharSequence printInfo(ChoiceSchemaNode node, int level, YangInstanceIdentifier path) '''
1051 «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
1052 «choiceCases.printChildren(level, path)»
1055 private def CharSequence printInfo(CaseSchemaNode node, int level, YangInstanceIdentifier path) '''
1056 «node.childNodes.printChildren(level, path)»
1061 def CharSequence printShortInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) {
1062 val newPath = path.append(node);
1064 <li>«strong(localLink(newPath,node.QName.localName))» (container)
1066 «node.configurationDataItem»
1072 def CharSequence printShortInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) {
1073 val newPath = path.append(node);
1075 <li>«strong(localLink(newPath,node.QName.localName))» (list)
1077 «node.configurationDataItem»
1083 def CharSequence printShortInfo(AnyxmlSchemaNode node, int level, YangInstanceIdentifier path) {
1085 <li>«strong((node.QName.localName))» (anyxml)
1087 «node.configurationDataItem»
1088 «node.mandatoryItem»
1094 def CharSequence printShortInfo(LeafSchemaNode node, int level, YangInstanceIdentifier path) {
1096 <li>«strong((node.QName.localName))» (leaf)
1098 «node.configurationDataItem»
1099 «node.mandatoryItem»
1105 def CharSequence printShortInfo(LeafListSchemaNode node, int level, YangInstanceIdentifier path) {
1107 <li>«strong((node.QName.localName))» (leaf-list)
1109 «node.configurationDataItem»
1115 def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
1117 <a href="#«anchor»">«text»</a>
1121 def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) '''
1122 <a href="#«FOR cmp : identifier.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
1125 private static def String configurationDataItem(DataSchemaNode node) {
1126 return node.effectiveConfig
1127 .map([config | "<li>configuration data: " + strong(String.valueOf(config)) + "</li>"])
1131 private static def CharSequence mandatoryItem(MandatoryAware node) '''
1132 <li>mandatory: «strong(String.valueOf(node.mandatory))»</li>
1135 private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ContainerSchemaNode node) {
1136 return identifier.node(node.QName);
1139 private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ListSchemaNode node) {
1140 val keyValues = new LinkedHashMap<QName,Object>();
1141 if(node.keyDefinition !== null) {
1142 for(definition : node.keyDefinition) {
1143 keyValues.put(definition,new Object);
1147 return identifier.node(NodeIdentifierWithPredicates.of(node.QName, keyValues));
1151 def asXmlPath(YangInstanceIdentifier identifier) {
1155 def asRestconfPath(YangInstanceIdentifier identifier) {
1156 val it = new StringBuilder();
1159 var previous = false;
1160 for(arg : identifier.pathArguments) {
1161 if(previous) append('/')
1162 append(arg.nodeType.localName);
1164 if(arg instanceof NodeIdentifierWithPredicates) {
1165 for(qname : arg.keySet) {
1167 append(qname.localName)
1176 private def String schemaPathToString(SchemaNodeIdentifier schemaPath, DataNodeContainer dataNode) {
1177 val path = schemaPath.nodeIdentifiers
1178 val StringBuilder pathString = new StringBuilder()
1179 if (schemaPath instanceof Absolute) {
1180 pathString.append('/')
1183 val QName qname = path.get(0)
1184 var Object parent = ctx.findModule(qname.module).orElse(null)
1187 if (parent instanceof DataNodeContainer) {
1188 var SchemaNode node = parent.dataChildByName(name)
1189 if (node === null && (parent instanceof Module)) {
1190 val notifications = (parent as Module).notifications;
1191 for (notification : notifications) {
1192 if (notification.QName.equals(name)) {
1197 if (node === null && (parent instanceof Module)) {
1198 val rpcs = (parent as Module).rpcs;
1200 if (rpc.QName.equals(name)) {
1206 val pathElementModule = ctx.findModule(name.module).get
1207 val String moduleName = pathElementModule.name
1208 pathString.append(moduleName)
1209 pathString.append(':')
1210 pathString.append(name.localName)
1211 pathString.append('/')
1212 if(node instanceof ChoiceSchemaNode && dataNode !== null) {
1213 val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof CaseSchemaNode];
1214 if(caseNode !== null) {
1215 pathString.append("(case)");
1216 pathString.append(caseNode.QName.localName);
1222 return pathString.toString;
1226 def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
1227 «IF childNodes !== null && !childNodes.empty»
1228 «FOR child : childNodes.values»
1229 «childInfo(child, childNodes)»
1234 def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
1235 «val String path = nodeSchemaPathToPath(node, childNodes)»
1246 private def CharSequence treeSet(Collection<? extends DataSchemaNode> childNodes, YangInstanceIdentifier path) '''
1247 «IF childNodes !== null && !childNodes.empty»
1249 «FOR child : childNodes»
1258 def listKeys(ListSchemaNode node) '''
1259 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
1262 private def CharSequence extensionInfo(ExtensionDefinition ext) '''
1265 «listItem("Argument", ext.argument)»
1270 /* #################### RESTRICTIONS #################### */
1271 private def restrictions(TypeDefinition<?> type) '''
1272 «type.baseType.toBaseStmt»
1277 private def toLength(TypeDefinition<?> type) '''
1278 «IF type instanceof LengthRestrictedTypeDefinition»
1279 «type.lengthConstraint.toLengthStmt»
1283 private def toRange(TypeDefinition<?> type) '''
1284 «IF type instanceof RangeRestrictedTypeDefinition»
1285 «type.rangeConstraint.toRangeStmt»
1289 def toLengthStmt(Optional<LengthConstraint> lengths) '''
1290 «IF lengths.isPresent»
1291 «listItem("Length restrictions:")»
1293 «FOR length : lengths.get.allowedRanges.asRanges»
1295 «IF length.lowerEndpoint.equals(length.upperEndpoint)»
1296 «length.lowerEndpoint»
1298 <«length.lowerEndpoint», «length.upperEndpoint»>
1306 def toRangeStmt(Optional<? extends RangeConstraint<?>> constraint) '''
1307 «IF constraint.present»
1308 «listItem("Range restrictions:")»
1310 «FOR range : constraint.get.allowedRanges.asRanges»
1312 «IF range.lowerEndpoint.equals(range.upperEndpoint)»
1313 «range.lowerEndpoint»
1315 <«range.lowerEndpoint», «range.upperEndpoint»>
1323 def toBaseStmt(TypeDefinition<?> baseType) '''
1324 «IF baseType !== null»
1325 «listItem("Base type", typeAnchorLink(types.get(baseType), baseType.QName.localName))»
1329 /* #################### UTILITY #################### */
1330 private def static String strong(CharSequence str) '''<strong>«str»</strong>'''
1331 private def static italic(CharSequence str) '''<i>«str»</i>'''
1333 def CharSequence descAndRefLi(SchemaNode node) '''
1334 «listItem("Description", node.description.orElse(null))»
1335 «listItem("Reference", node.reference.orElse(null))»
1338 def CharSequence descAndRef(SchemaNode node) '''
1340 «IF node.reference !== null»
1341 Reference «node.reference»
1345 private def listItem(String value) '''
1346 «IF value !== null && !value.empty»
1353 private def listItem(String name, String value) '''
1354 «IF value !== null && !value.empty»
1361 private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
1362 if (node instanceof ChoiceSchemaNode || node instanceof CaseSchemaNode) {
1366 val path = node.path.pathFromRoot
1367 val absolute = node.path.absolute;
1368 var StringBuilder result = new StringBuilder
1372 if (path !== null && !path.empty) {
1373 val actual = new ArrayList()
1375 for (pathElement : path) {
1376 actual.add(pathElement)
1377 val DataSchemaNode nodeByPath = childNodes.get(SchemaPath.create(actual, absolute))
1378 if (!(nodeByPath instanceof ChoiceSchemaNode) && !(nodeByPath instanceof CaseSchemaNode)) {
1379 result.append(pathElement.localName)
1380 if (i != path.size - 1) {
1387 return result.toString
1390 private def addedByInfo(SchemaNode node) {
1391 if (node instanceof DataSchemaNode) {
1392 return addedByInfo(node)
1397 private def addedByInfo(DataSchemaNode node) '''
1398 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
1401 private def isAddedBy(SchemaNode node) {
1402 if (node instanceof DataSchemaNode) {
1403 return node.augmenting || node.addedByUses
1408 private def nodeName(SchemaNode node) {
1409 if (node instanceof ContainerSchemaNode) {
1410 return nodeName(node);
1411 } else if (node instanceof ListSchemaNode) {
1412 return nodeName(node);
1414 val addedByInfo = node.addedByInfo
1415 if (node.isAddedBy) {
1416 return '''«italic(node.QName.localName)»«addedByInfo»'''
1418 return '''«node.QName.localName»«addedByInfo»'''
1421 private def nodeName(ContainerSchemaNode node) '''
1423 «strong(italic(node.QName.localName))»«node.addedByInfo»
1425 «strong(node.QName.localName)»«node.addedByInfo»
1429 private def nodeName(ListSchemaNode node) '''
1431 «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
1433 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»