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.yangtools.yang.unified.doc.generator
10 import java.io.BufferedWriter
12 import java.io.IOException
13 import java.io.OutputStreamWriter
14 import java.text.SimpleDateFormat
15 import java.util.ArrayList
16 import java.util.Collection
17 import java.util.HashMap
18 import java.util.HashSet
19 import java.util.LinkedHashMap
23 import org.opendaylight.yangtools.yang.common.QName
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.ChoiceCaseNode
27 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
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.ExtensionDefinition
32 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
33 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
34 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
35 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
36 import org.opendaylight.yangtools.yang.model.api.Module
37 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext
39 import org.opendaylight.yangtools.yang.model.api.SchemaNode
40 import org.opendaylight.yangtools.yang.model.api.SchemaPath
41 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
42 import org.opendaylight.yangtools.yang.model.api.UsesNode
43 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
44 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
45 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
46 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
47 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
48 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
49 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
50 import org.opendaylight.yangtools.yang.model.util.ExtendedType
51 import org.slf4j.Logger
52 import org.slf4j.LoggerFactory
53 import org.sonatype.plexus.build.incremental.BuildContext
54 import org.sonatype.plexus.build.incremental.DefaultBuildContext
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates
56 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
57 import com.google.common.collect.Iterables
62 static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
63 static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
64 static val BuildContext CTX = new DefaultBuildContext();
65 var Module currentModule;
66 val Map<String, String> imports = new HashMap();
67 var SchemaContext ctx;
69 StringBuilder augmentChildNodesAsString
71 DataSchemaNode lastNodeInTargetPath = null
73 def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
77 for (module : modulesToGen) {
78 add(generateDocumentation(module, context));
83 def generateDocumentation(Module module, SchemaContext ctx) {
84 val destination = new File(path, '''«module.name».html''')
86 module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
88 val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
89 val bw = new BufferedWriter(fw)
90 currentModule = module;
91 bw.append(generate(module, ctx));
94 } catch (IOException e) {
95 LOG.error(e.getMessage());
100 def generate(Module module, SchemaContext ctx) '''
104 <title>«module.name»</title>
112 def body(Module module, SchemaContext ctx) '''
115 «typeDefinitionsSummary(module)»
116 «identitiesSummary(module)»
117 «groupingsSummary(module)»
118 «augmentationsSummary(module, ctx)»
119 «objectsSummary(module)»
120 «notificationsSummary(module)»
121 «rpcsSummary(module)»
122 «extensionsSummary(module)»
123 «featuresSummary(module)»
125 «typeDefinitions(module)»
135 «notifications(module)»
137 «augmentations(module, ctx)»
148 private def typeDefinitionsSummary(Module module) {
149 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
150 if (typedefs.empty) {
155 <h3>Type Definitions Summary</h3>
161 «FOR typedef : typedefs»
164 «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
167 «typedef.description»
176 def typeDefinitions(Module module) {
177 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
178 if (typedefs.empty) {
182 <h2>Type Definitions</h2>
184 «FOR typedef : typedefs»
186 <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
188 «typedef.descAndRefLi»
189 «typedef.restrictions»
197 private def identities(Module module) {
198 if (module.identities.empty) {
204 «FOR identity : module.identities»
206 <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
208 «identity.descAndRefLi»
209 «IF identity.baseIdentity !== null»
210 «listItem("base", identity.baseIdentity.QName.localName)»
219 private def identitiesSummary(Module module) {
220 if (module.identities.empty) {
224 <h3>Identities Summary</h3>
230 «FOR identity : module.identities»
233 «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
236 «identity.description»
244 private def groupings(Module module) {
245 if (module.groupings.empty) {
251 «FOR grouping : module.groupings»
253 <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
255 «grouping.descAndRefLi»
256 «FOR childNode : grouping.childNodes»
257 «childNode.printSchemaNodeInfo»
266 private def groupingsSummary(Module module) {
267 if (module.groupings.empty) {
271 <h3>Groupings Summary</h3>
277 «FOR grouping : module.groupings»
280 «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
283 «grouping.description»
291 def dataStore(Module module) {
292 if (module.childNodes.empty) {
296 <h2>Datastore Structure</h2>
301 def augmentations(Module module, SchemaContext context) {
302 if (module.augmentations.empty) {
306 <h2>Augmentations</h2>
309 «FOR augment : module.augmentations»
311 <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
312 Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
313 «augment.description»
314 Status: «strong(String.valueOf(augment.status))»
315 «IF augment.reference !== null»
316 Reference «augment.reference»
318 «IF augment.whenCondition !== null»
319 When «augment.whenCondition.toString»
321 «FOR childNode : augment.childNodes»
322 «childNode.printSchemaNodeInfo»
326 «createAugmentChildNodesAsString(new ArrayList(augment.childNodes))»
327 «printNodeChildren(parseTargetPath(augment.targetPath))»
334 private def createAugmentChildNodesAsString(List<DataSchemaNode> childNodes) {
335 augmentChildNodesAsString = new StringBuilder();
336 augmentChildNodesAsString.append(printNodeChildren(childNodes))
340 private def parseTargetPath(SchemaPath path) {
341 val List<DataSchemaNode> nodes = new ArrayList<DataSchemaNode>();
342 for (QName pathElement : path.pathFromRoot) {
343 val module = ctx.findModuleByNamespaceAndRevision(pathElement.namespace, pathElement.revision);
344 if (module !== null) {
345 var foundNode = module.getDataChildByName(pathElement)
346 if(foundNode == null) {
347 val child = nodes.last
348 if (child instanceof DataNodeContainer) {
349 val dataContNode = child as DataNodeContainer
350 foundNode = findNodeInChildNodes(pathElement, dataContNode.childNodes)
353 if(foundNode != null) {
354 nodes.add(foundNode);
359 lastNodeInTargetPath = nodes.get(nodes.size() - 1)
362 val List<DataSchemaNode> targetPathNodes = new ArrayList<DataSchemaNode>();
363 targetPathNodes.add(lastNodeInTargetPath)
365 return targetPathNodes
368 private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable<DataSchemaNode> childNodes) {
369 for(child : childNodes) {
370 if (child.QName.equals(findingNode))
374 for(child : childNodes) {
375 if(child instanceof ContainerSchemaNode) {
376 val contChild = child as ContainerSchemaNode
377 val foundChild = findNodeInChildNodes(findingNode, contChild.childNodes)
378 if (foundChild != null)
381 else if(child instanceof ListSchemaNode) {
382 val listChild = child as ListSchemaNode
383 val foundChild = findNodeInChildNodes(findingNode, listChild.childNodes)
384 if (foundChild != null)
390 private def printNodeChildren(List<DataSchemaNode> childNodes) {
391 if (childNodes.empty) {
398 «printAugmentedNode(childNodes.get(0))»
403 private def printAugmentedNode(DataSchemaNode child) {
405 if(child instanceof ChoiceCaseNode)
410 «IF child instanceof ContainerSchemaNode»
411 «printContainerNode(child as ContainerSchemaNode)»
413 «IF child instanceof AnyXmlSchemaNode»
414 «printAnyXmlNode(child as AnyXmlSchemaNode)»
416 «IF child instanceof LeafSchemaNode»
417 «printLeafNode(child as LeafSchemaNode)»
419 «IF child instanceof LeafListSchemaNode»
420 «printLeafListNode(child as LeafListSchemaNode)»
422 «IF child instanceof ListSchemaNode»
423 «printListNode(child as ListSchemaNode)»
425 «IF child instanceof ChoiceNode»
426 «printChoiceNode(child as ChoiceNode)»
431 private def printChoiceNode(ChoiceNode child) {
432 val List<ChoiceCaseNode> cases = new ArrayList(child.cases);
434 val ChoiceCaseNode aCase = cases.get(0)
435 for(caseChildNode : aCase.childNodes)
436 printAugmentedNode(caseChildNode)
440 private def printListNode(ListSchemaNode listNode) {
443 <«listNode.QName.localName»«IF !listNode.QName.namespace.equals(currentModule.namespace)» xmlns="«listNode.QName.namespace»"«ENDIF»>
444 «FOR child : listNode.childNodes»
445 «printAugmentedNode(child)»
447 </«listNode.QName.localName»>
451 private def printContainerNode(ContainerSchemaNode containerNode) {
454 <«containerNode.QName.localName»«IF !containerNode.QName.namespace.equals(currentModule.namespace)» xmlns="«containerNode.QName.namespace»"«ENDIF»>
455 «FOR child : containerNode.childNodes»
456 «printAugmentedNode(child)»
458 </«containerNode.QName.localName»>
462 private def printLeafListNode(LeafListSchemaNode leafListNode) {
465 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
466 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
467 <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»>
471 private def printAnyXmlNode(AnyXmlSchemaNode anyXmlNode) {
474 <«anyXmlNode.QName.localName»>. . .</«anyXmlNode.QName.localName»>
478 private def printLeafNode(LeafSchemaNode leafNode) {
481 <«leafNode.QName.localName»>. . .</«leafNode.QName.localName»>
485 private def augmentationsSummary(Module module, SchemaContext context) {
486 if (module.augmentations.empty) {
490 <h3>Augmentations Summary</h3>
496 «FOR augment : module.augmentations»
499 «anchorLink(schemaPathToString(module, augment.targetPath, context, augment),
500 strong(schemaPathToString(module, augment.targetPath, context, augment)))»
503 «augment.description»
511 def notifications(Module module) {
512 val Set<NotificationDefinition> notificationdefs = module.notifications
513 if (notificationdefs.empty) {
518 <h2>Notifications</h2>
519 «FOR notificationdef : notificationdefs»
521 <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
522 «notificationdef.descAndRef»
523 «FOR childNode : notificationdef.childNodes»
524 «childNode.printSchemaNodeInfo»
530 private def notificationsSummary(Module module) {
531 if (module.notifications.empty) {
535 <h3>Notifications Summary</h3>
541 «FOR notification : module.notifications»
544 «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
547 «notification.description»
555 def rpcs(Module module) {
556 if (module.rpcs.empty) {
561 <h2>RPC Definitions</h2>
562 «FOR rpc : module.rpcs»
563 <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
566 «rpc.input.printSchemaNodeInfo»
567 «rpc.output.printSchemaNodeInfo»
574 private def rpcsSummary(Module module) {
575 if (module.rpcs.empty) {
579 <h3>RPCs Summary</h3>
585 «FOR rpc : module.rpcs»
588 «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
599 def extensions(Module module) {
600 if (module.extensionSchemaNodes.empty) {
605 «FOR ext : module.extensionSchemaNodes»
607 <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
614 private def extensionsSummary(Module module) {
615 if (module.extensionSchemaNodes.empty) {
619 <h3>Extensions Summary</h3>
625 «FOR ext : module.extensionSchemaNodes»
628 «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
639 def features(Module module) {
640 if (module.features.empty) {
647 «FOR feature : module.features»
649 <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
651 «feature.descAndRefLi»
659 private def featuresSummary(Module module) {
660 if (module.features.empty) {
664 <h3>Features Summary</h3>
670 «FOR feature : module.features»
673 «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
676 «feature.description»
684 private def objectsSummary(Module module) {
685 if (module.childNodes.empty) {
689 <h3>Child Nodes Summary</h3>
695 «FOR childNode : module.childNodes»
698 «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
701 «childNode.description»
709 def header(Module module)
711 <h1>«module.name»</h1>
713 <h2>Base Information</h2>
716 <td>«strong("prefix")»</td>
717 <td>«module.prefix»</td>
720 <td>«strong("namespace")»</td>
721 <td>«module.namespace»</td>
724 <td>«strong("revision")»</td>
725 <td>«REVISION_FORMAT.format(module.revision)»</td>
728 <td>«strong("description")»</td>
729 <td>«module.description»</td>
732 <td>«strong("yang-version")»</td>
733 <td>«module.yangVersion»</td>
736 «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
737 «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
743 def CharSequence schemaPathToId(SchemaPath path) {
745 return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»'''
749 def code(String string) '''<code>«string»</code>'''
751 def process(Module module) {
752 throw new UnsupportedOperationException("TODO: auto-generated method stub")
755 def CharSequence tree(Module module) '''
756 «strong(module.name)»
757 «module.childNodes.treeSet(YangInstanceIdentifier.builder.toInstance())»
760 private def dispatch CharSequence tree(ChoiceNode node,YangInstanceIdentifier path) '''
761 «node.nodeName» (choice)
762 «casesTree(node.cases,path)»
765 def casesTree(Set<ChoiceCaseNode> nodes,YangInstanceIdentifier path) '''
770 «node.childNodes.treeSet(path)»
776 private def dispatch CharSequence tree(DataSchemaNode node,YangInstanceIdentifier path) '''
780 private def dispatch CharSequence tree(ListSchemaNode node,YangInstanceIdentifier path) '''
781 «val newPath = path.append(node)»
782 «localLink(newPath,node.nodeName)»
783 «node.childNodes.treeSet(newPath)»
786 private def dispatch CharSequence tree(ContainerSchemaNode node,YangInstanceIdentifier path) '''
787 «val newPath = path.append(node)»
788 «localLink(newPath,node.nodeName)»
789 «node.childNodes.treeSet(newPath)»
792 def CharSequence childNodes(Module module) '''
793 «val childNodes = module.childNodes»
794 «IF !childNodes.nullOrEmpty»
797 «childNodes.printChildren(3,YangInstanceIdentifier.builder().toInstance())»
801 def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
805 «IF node instanceof DataNodeContainer»
806 «val dataNode = node as DataNodeContainer»
808 «FOR usesNode : dataNode.uses»
813 «FOR typeDef : dataNode.typeDefinitions»
814 «typeDef.restrictions»
818 «FOR grouping : dataNode.groupings»
819 «grouping.printGrouping»
823 «FOR child : dataNode.childNodes»
824 «child.printSchemaNodeInfo»
832 def String typeAnchorLink(SchemaPath path, CharSequence text) {
834 val lastElement = Iterables.getLast(path.pathFromRoot)
835 val ns = lastElement.namespace
836 if (ns == this.currentModule.namespace) {
837 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
839 return '''(«ns»)«text»'''
840 //to enable external (import) links
841 //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
846 def CharSequence printBaseInfo(SchemaNode node) {
847 if(node instanceof LeafSchemaNode) {
848 val LeafSchemaNode leafNode = (node as LeafSchemaNode)
850 «printInfo(node, "leaf")»
851 «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
852 «listItem("units", leafNode.units)»
853 «listItem("default", leafNode.^default)»
856 } else if(node instanceof LeafListSchemaNode) {
857 val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
859 «printInfo(node, "leaf-list")»
860 «listItem("type", leafListNode.type?.QName.localName)»
863 } else if(node instanceof ListSchemaNode) {
864 val ListSchemaNode listNode = (node as ListSchemaNode)
866 «printInfo(node, "list")»
867 «FOR keyDef : listNode.keyDefinition»
868 «listItem("key definition", keyDef.localName)»
872 } else if(node instanceof ChoiceNode) {
873 val ChoiceNode choiceNode = (node as ChoiceNode)
875 «printInfo(node, "choice")»
876 «listItem("default case", choiceNode.defaultCase)»
877 «FOR caseNode : choiceNode.cases»
878 «caseNode.printSchemaNodeInfo»
882 } else if(node instanceof ChoiceCaseNode) {
884 «printInfo(node, "case")»
887 } else if(node instanceof ContainerSchemaNode) {
889 «printInfo(node, "container")»
892 } else if(node instanceof AnyXmlSchemaNode) {
894 «printInfo(node, "anyxml")»
900 def CharSequence printInfo(SchemaNode node, String nodeType) {
902 «IF node instanceof AugmentationTarget»
905 <li id="«node.path.schemaPathToId»">
906 «nodeType»: «node.QName.localName»
911 «strong(listItem(nodeType, node.QName.localName))»
914 «listItem("description", node.description)»
915 «listItem("reference", node.reference)»
916 «IF node instanceof DataSchemaNode»
917 «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
918 «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
919 «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
924 def CharSequence printUses(UsesNode usesNode) {
926 «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.pathTowardsRoot.iterator.next.localName)))»
930 «FOR sp : usesNode.refines.keySet»
931 «listItem("node name", usesNode.refines.get(sp).QName.localName)»
935 «FOR augment : usesNode.augmentations»
936 «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
942 def CharSequence printGrouping(GroupingDefinition grouping) {
944 «strong(listItem("grouping", grouping.QName.localName))»
948 def CharSequence printChildren(Iterable<DataSchemaNode> nodes, int level, YangInstanceIdentifier path) {
949 val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
950 val leafNodes = nodes.filter(LeafSchemaNode)
951 val leafListNodes = nodes.filter(LeafListSchemaNode)
952 val choices = nodes.filter(ChoiceNode)
953 val cases = nodes.filter(ChoiceCaseNode)
954 val containers = nodes.filter(ContainerSchemaNode)
955 val lists = nodes.filter(ListSchemaNode)
957 «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
958 <h3>Direct children</h3>
960 «FOR childNode : anyxmlNodes»
961 «childNode.printShortInfo(level,path)»
963 «FOR childNode : leafNodes»
964 «childNode.printShortInfo(level,path)»
966 «FOR childNode : leafListNodes»
967 «childNode.printShortInfo(level,path)»
969 «FOR childNode : containers»
970 «childNode.printShortInfo(level,path)»
972 «FOR childNode : lists»
973 «childNode.printShortInfo(level,path)»
978 «IF !path.path.empty»
980 «nodes.xmlExample(path.path.last.nodeType,path)»
983 «FOR childNode : containers»
984 «childNode.printInfo(level,path)»
986 «FOR childNode : lists»
987 «childNode.printInfo(level,path)»
989 «FOR childNode : choices»
990 «childNode.printInfo(level,path)»
992 «FOR childNode : cases»
993 «childNode.printInfo(level,path)»
998 def CharSequence xmlExample(Iterable<DataSchemaNode> nodes, QName name,YangInstanceIdentifier path) '''
1000 «xmlExampleTag(name,nodes.xmplExampleTags(path))»
1004 def CharSequence xmplExampleTags(Iterable<DataSchemaNode> nodes, YangInstanceIdentifier identifier) '''
1005 <!-- Child nodes -->
1007 <!-- «node.QName.localName» -->
1008 «node.asXmlExampleTag(identifier)»
1013 private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, YangInstanceIdentifier identifier) '''
1014 «node.QName.xmlExampleTag("...")»
1017 private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, YangInstanceIdentifier identifier) '''
1018 <!-- This node could appear multiple times -->
1019 «node.QName.xmlExampleTag("...")»
1022 private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, YangInstanceIdentifier identifier) '''
1023 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
1024 «node.QName.xmlExampleTag("...")»
1028 private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, YangInstanceIdentifier identifier) '''
1029 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
1030 <!-- This node could appear multiple times -->
1031 «node.QName.xmlExampleTag("...")»
1035 private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) '''
1040 def xmlExampleTag(QName name, CharSequence data) {
1041 return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
1044 def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''
1047 def header(int level,YangInstanceIdentifier name) '''
1048 <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
1049 «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
1055 private def dispatch CharSequence printInfo(DataSchemaNode node, int level, YangInstanceIdentifier path) '''
1056 «header(level+1,node.QName)»
1059 private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) '''
1060 «val newPath = path.append(node)»
1061 «header(level,newPath)»
1064 <dd>«newPath.asXmlPath»</dd>
1065 <dt>Restconf path</dt>
1066 <dd>«code(newPath.asRestconfPath)»</dd>
1068 «node.childNodes.printChildren(level,newPath)»
1071 private def dispatch CharSequence printInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) '''
1072 «val newPath = path.append(node)»
1073 «header(level,newPath)»
1076 <dd>«newPath.asXmlPath»</dd>
1077 <dt>Restconf path</dt>
1078 <dd>«code(newPath.asRestconfPath)»</dd>
1080 «node.childNodes.printChildren(level,newPath)»
1083 private def dispatch CharSequence printInfo(ChoiceNode node, int level, YangInstanceIdentifier path) '''
1084 «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
1085 «choiceCases.printChildren(level,path)»
1088 private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, YangInstanceIdentifier path) '''
1089 «node.childNodes.printChildren(level,path)»
1094 def CharSequence printShortInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) {
1095 val newPath = path.append(node);
1097 <li>«strong(localLink(newPath,node.QName.localName))» (container)
1099 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
1105 def CharSequence printShortInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) {
1106 val newPath = path.append(node);
1108 <li>«strong(localLink(newPath,node.QName.localName))» (list)
1110 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
1116 def CharSequence printShortInfo(AnyXmlSchemaNode node, int level, YangInstanceIdentifier path) {
1118 <li>«strong((node.QName.localName))» (anyxml)
1120 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
1121 <li>mandatory: «strong(String.valueOf(node.constraints.mandatory))»</li>
1127 def CharSequence printShortInfo(LeafSchemaNode node, int level, YangInstanceIdentifier path) {
1129 <li>«strong((node.QName.localName))» (leaf)
1131 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
1132 <li>mandatory: «strong(String.valueOf(node.constraints.mandatory))»</li>
1138 def CharSequence printShortInfo(LeafListSchemaNode node, int level, YangInstanceIdentifier path) {
1140 <li>«strong((node.QName.localName))» (leaf-list)
1142 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
1148 def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
1150 <a href="#«anchor»">«text»</a>
1154 def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) '''
1155 <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
1159 private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ContainerSchemaNode node) {
1160 return identifier.node(node.QName);
1163 private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ListSchemaNode node) {
1164 val keyValues = new LinkedHashMap<QName,Object>();
1165 if(node.keyDefinition !== null) {
1166 for(definition : node.keyDefinition) {
1167 keyValues.put(definition,new Object);
1171 return identifier.node(new NodeIdentifierWithPredicates(node.QName, keyValues));
1175 def asXmlPath(YangInstanceIdentifier identifier) {
1179 def asRestconfPath(YangInstanceIdentifier identifier) {
1180 val it = new StringBuilder();
1181 append(currentModule.name)
1183 var previous = false;
1184 for(arg : identifier.path) {
1185 if(previous) append("/")
1186 append(arg.nodeType.localName);
1188 if(arg instanceof NodeIdentifierWithPredicates) {
1189 val nodeIdentifier = arg as NodeIdentifierWithPredicates;
1190 for(qname : nodeIdentifier.getKeyValues.keySet) {
1192 append(qname.localName)
1201 private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
1202 val List<QName> path = schemaPath.path
1203 val StringBuilder pathString = new StringBuilder()
1204 if (schemaPath.absolute) {
1205 pathString.append('/')
1208 val QName qname = path.get(0)
1209 var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision)
1212 if (parent instanceof DataNodeContainer) {
1213 var SchemaNode node = (parent as DataNodeContainer).getDataChildByName(name)
1214 if (node == null && (parent instanceof Module)) {
1215 val notifications = (parent as Module).notifications;
1216 for (notification : notifications) {
1217 if (notification.QName.equals(name)) {
1222 if (node == null && (parent instanceof Module)) {
1223 val rpcs = (parent as Module).rpcs;
1225 if (rpc.QName.equals(name)) {
1231 val pathElementModule = ctx.findModuleByNamespaceAndRevision(name.namespace, name.revision)
1232 val String moduleName = pathElementModule.name
1233 pathString.append(moduleName)
1234 pathString.append(':')
1235 pathString.append(name.localName)
1236 pathString.append('/')
1237 if(node instanceof ChoiceNode && dataNode !== null) {
1238 val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode];
1239 if(caseNode !== null) {
1240 pathString.append("(case)");
1241 pathString.append(caseNode.QName.localName);
1247 return pathString.toString;
1251 def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
1252 «IF childNodes !== null && !childNodes.empty»
1253 «FOR child : childNodes.values»
1254 «childInfo(child, childNodes)»
1259 def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
1260 «val String path = nodeSchemaPathToPath(node, childNodes)»
1271 private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, YangInstanceIdentifier path) '''
1272 «IF childNodes !== null && !childNodes.empty»
1274 «FOR child : childNodes»
1283 def listKeys(ListSchemaNode node) '''
1284 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
1287 private def CharSequence extensionInfo(ExtensionDefinition ext) '''
1290 «listItem("Argument", ext.argument)»
1294 private def dispatch CharSequence tree(Void obj, YangInstanceIdentifier path) '''
1299 /* #################### RESTRICTIONS #################### */
1300 private def restrictions(TypeDefinition<?> type) '''
1301 «type.baseType.toBaseStmt»
1306 private def dispatch toLength(TypeDefinition<?> type) {
1309 private def dispatch toLength(BinaryTypeDefinition type) '''
1310 «type.lengthConstraints.toLengthStmt»
1313 private def dispatch toLength(StringTypeDefinition type) '''
1314 «type.lengthConstraints.toLengthStmt»
1317 private def dispatch toLength(ExtendedType type) '''
1318 «type.lengthConstraints.toLengthStmt»
1321 private def dispatch toRange(TypeDefinition<?> type) {
1324 private def dispatch toRange(DecimalTypeDefinition type) '''
1325 «type.rangeConstraints.toRangeStmt»
1328 private def dispatch toRange(IntegerTypeDefinition type) '''
1329 «type.rangeConstraints.toRangeStmt»
1332 private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
1333 «type.rangeConstraints.toRangeStmt»
1336 private def dispatch toRange(ExtendedType type) '''
1337 «type.rangeConstraints.toRangeStmt»
1340 def toLengthStmt(Collection<LengthConstraint> lengths) '''
1341 «IF lengths != null && !lengths.empty»
1342 «listItem("Length restrictions:")»
1344 «FOR length : lengths»
1346 «IF length.min == length.max»
1349 <«length.min», «length.max»>
1357 def toRangeStmt(Collection<RangeConstraint> ranges) '''
1358 «IF ranges != null && !ranges.empty»
1359 «listItem("Range restrictions:")»
1361 «FOR range : ranges»
1363 «IF range.min == range.max»
1366 <«range.min», «range.max»>
1374 def toBaseStmt(TypeDefinition<?> baseType) '''
1375 «IF baseType != null»
1376 «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))»
1382 /* #################### UTILITY #################### */
1383 private def String strong(CharSequence str) '''<strong>«str»</strong>'''
1384 private def italic(CharSequence str) '''<i>«str»</i>'''
1386 def CharSequence descAndRefLi(SchemaNode node) '''
1387 «listItem("Description", node.description)»
1388 «listItem("Reference", node.reference)»
1391 def CharSequence descAndRef(SchemaNode node) '''
1393 «IF node.reference !== null»
1394 Reference «node.reference»
1398 private def listItem(String value) '''
1399 «IF value !== null && !value.empty»
1406 private def listItem(String name, String value) '''
1407 «IF value !== null && !value.empty»
1414 private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
1415 if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {
1419 val path = node.path.path
1420 val absolute = node.path.absolute;
1421 var StringBuilder result = new StringBuilder
1425 if (path !== null && !path.empty) {
1426 val List<QName> actual = new ArrayList()
1428 for (pathElement : path) {
1429 actual.add(pathElement)
1430 val DataSchemaNode nodeByPath = childNodes.get(SchemaPath.create(actual, absolute))
1431 if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {
1432 result.append(pathElement.localName)
1433 if (i != path.size - 1) {
1440 return result.toString
1443 private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {
1444 for (node : source) {
1445 destination.put(node.path, node)
1446 if (node instanceof DataNodeContainer) {
1447 collectChildNodes((node as DataNodeContainer).childNodes, destination)
1449 if (node instanceof ChoiceNode) {
1450 val List<DataSchemaNode> choiceCases = new ArrayList()
1451 for (caseNode : (node as ChoiceNode).cases) {
1452 choiceCases.add(caseNode)
1454 collectChildNodes(choiceCases, destination)
1459 private def dispatch addedByInfo(SchemaNode node) '''
1462 private def dispatch addedByInfo(DataSchemaNode node) '''
1463 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
1466 private def dispatch isAddedBy(SchemaNode node) {
1470 private def dispatch isAddedBy(DataSchemaNode node) {
1471 if (node.augmenting || node.addedByUses) {
1478 private def dispatch nodeName(SchemaNode node) '''
1480 «italic(node.QName.localName)»«node.addedByInfo»
1482 «node.QName.localName»«node.addedByInfo»
1486 private def dispatch nodeName(ContainerSchemaNode node) '''
1488 «strong(italic(node.QName.localName))»«node.addedByInfo»
1490 «strong(node.QName.localName)»«node.addedByInfo»
1494 private def dispatch nodeName(ListSchemaNode node) '''
1496 «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
1498 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»