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 org.opendaylight.yangtools.yang.model.api.SchemaContext
13 import org.opendaylight.yangtools.yang.model.api.Module
14 import java.io.IOException
15 import java.util.HashSet
16 import java.io.BufferedWriter
17 import java.io.OutputStreamWriter;
18 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
19 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
20 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
21 import org.opendaylight.yangtools.yang.model.api.SchemaNode
22 import org.opendaylight.yangtools.yang.model.util.ExtendedType
23 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
24 import java.text.SimpleDateFormat
25 import java.util.Collection
26 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
27 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
28 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
29 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
30 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
31 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
32 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
34 import org.slf4j.LoggerFactory
35 import org.slf4j.Logger
37 import org.opendaylight.yangtools.yang.common.QName
38 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
39 import java.util.ArrayList
41 import org.opendaylight.yangtools.yang.model.api.SchemaPath
43 import org.sonatype.plexus.build.incremental.BuildContext;
44 import org.sonatype.plexus.build.incremental.DefaultBuildContext;
46 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
47 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
48 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
49 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
50 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
51 import java.util.LinkedHashMap
52 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier
53 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode
54 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode
\rimport java.util.HashMap
55 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
56 import org.opendaylight.yangtools.yang.model.api.UsesNode
57 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition
58 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
63 static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
64 static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
65 static val BuildContext CTX = new DefaultBuildContext();
66 var Module currentModule;
67 val Map<String, String> imports = new HashMap();
68 var SchemaContext ctx;
70 def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
74 for (module : modulesToGen) {
75 add(generateDocumentation(module, context));
80 def generateDocumentation(Module module, SchemaContext ctx) {
81 val destination = new File(path, '''«module.name».html''')
83 module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
85 val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
86 val bw = new BufferedWriter(fw)
87 currentModule = module;
88 bw.append(generate(module, ctx));
91 } catch (IOException e) {
92 LOG.error(e.getMessage());
97 def generate(Module module, SchemaContext ctx) '''
101 <title>«module.name»</title>
109 def body(Module module, SchemaContext ctx) '''
112 «typeDefinitionsSummary(module)»
113 «identitiesSummary(module)»
114 «groupingsSummary(module)»
115 «augmentationsSummary(module, ctx)»
116 «objectsSummary(module)»
117 «notificationsSummary(module)»
118 «rpcsSummary(module)»
119 «extensionsSummary(module)»
120 «featuresSummary(module)»
122 «typeDefinitions(module)»
132 «notifications(module)»
134 «augmentations(module, ctx)»
145 private def typeDefinitionsSummary(Module module) {
146 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
147 if (typedefs.empty) {
152 <h3>Type Definitions Summary</h3>
158 «FOR typedef : typedefs»
161 «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
164 «typedef.description»
173 def typeDefinitions(Module module) {
174 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
175 if (typedefs.empty) {
179 <h2>Type Definitions</h2>
181 «FOR typedef : typedefs»
183 <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
185 «typedef.descAndRefLi»
186 «typedef.restrictions»
194 private def identities(Module module) {
195 if (module.identities.empty) {
201 «FOR identity : module.identities»
203 <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
205 «identity.descAndRefLi»
206 «IF identity.baseIdentity !== null»
207 «listItem("base", identity.baseIdentity.QName.localName)»
216 private def identitiesSummary(Module module) {
217 if (module.identities.empty) {
221 <h3>Identities Summary</h3>
227 «FOR identity : module.identities»
230 «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
233 «identity.description»
241 private def groupings(Module module) {
242 if (module.groupings.empty) {
248 «FOR grouping : module.groupings»
250 <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
252 «grouping.descAndRefLi»
253 «FOR childNode : grouping.childNodes»
254 «childNode.printSchemaNodeInfo»
263 private def groupingsSummary(Module module) {
264 if (module.groupings.empty) {
268 <h3>Groupings Summary</h3>
274 «FOR grouping : module.groupings»
277 «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
280 «grouping.description»
288 def dataStore(Module module) {
289 if (module.childNodes.empty) {
293 <h2>Datastore Structure</h2>
298 def augmentations(Module module, SchemaContext context) {
299 if (module.augmentations.empty) {
303 <h2>Augmentations</h2>
306 «FOR augment : module.augmentations»
308 <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
309 Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
310 «augment.description»
311 «IF augment.reference !== null»
312 Reference «augment.reference»
314 «IF augment.whenCondition !== null»
315 When «augment.whenCondition.toString»
317 «FOR childNode : augment.childNodes»
318 «childNode.printSchemaNodeInfo»
326 private def augmentationsSummary(Module module, SchemaContext context) {
327 if (module.augmentations.empty) {
331 <h3>Augmentations Summary</h3>
337 «FOR augment : module.augmentations»
340 «anchorLink(schemaPathToString(module, augment.targetPath, context, augment),
341 strong(schemaPathToString(module, augment.targetPath, context, augment)))»
344 «augment.description»
352 def notifications(Module module) {
353 val Set<NotificationDefinition> notificationdefs = module.notifications
354 if (notificationdefs.empty) {
359 <h2>Notifications</h2>
360 «FOR notificationdef : notificationdefs»
362 <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
363 «notificationdef.descAndRef»
364 «FOR childNode : notificationdef.childNodes»
365 «childNode.printSchemaNodeInfo»
371 private def notificationsSummary(Module module) {
372 if (module.notifications.empty) {
376 <h3>Notifications Summary</h3>
382 «FOR notification : module.notifications»
385 «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
388 «notification.description»
396 def rpcs(Module module) {
397 if (module.rpcs.empty) {
402 <h2>RPC Definitions</h2>
403 «FOR rpc : module.rpcs»
404 <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
407 «rpc.input.printSchemaNodeInfo»
408 «rpc.output.printSchemaNodeInfo»
415 private def rpcsSummary(Module module) {
416 if (module.rpcs.empty) {
420 <h3>RPCs Summary</h3>
426 «FOR rpc : module.rpcs»
429 «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
440 def extensions(Module module) {
441 if (module.extensionSchemaNodes.empty) {
446 «FOR ext : module.extensionSchemaNodes»
448 <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
455 private def extensionsSummary(Module module) {
456 if (module.extensionSchemaNodes.empty) {
460 <h3>Extensions Summary</h3>
466 «FOR ext : module.extensionSchemaNodes»
469 «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
480 def features(Module module) {
481 if (module.features.empty) {
488 «FOR feature : module.features»
490 <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
492 «feature.descAndRefLi»
500 private def featuresSummary(Module module) {
501 if (module.features.empty) {
505 <h3>Features Summary</h3>
511 «FOR feature : module.features»
514 «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
517 «feature.description»
525 private def objectsSummary(Module module) {
526 if (module.childNodes.empty) {
530 <h3>Child Nodes Summary</h3>
536 «FOR childNode : module.childNodes»
539 «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
542 «childNode.description»
550 def header(Module module)
552 <h1>«module.name»</h1>
554 <h2>Base Information</h2>
557 <td>«strong("prefix")»</td>
558 <td>«module.prefix»</td>
561 <td>«strong("namespace")»</td>
562 <td>«module.namespace»</td>
565 <td>«strong("revision")»</td>
566 <td>«REVISION_FORMAT.format(module.revision)»</td>
569 <td>«strong("description")»</td>
570 <td>«module.description»</td>
573 <td>«strong("yang-version")»</td>
574 <td>«module.yangVersion»</td>
577 «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
578 «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
584 def CharSequence schemaPathToId(SchemaPath path) {
586 return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»'''
590 def code(String string) '''<code>«string»</code>'''
592 def process(Module module) {
593 throw new UnsupportedOperationException("TODO: auto-generated method stub")
596 def CharSequence tree(Module module) '''
597 «strong(module.name)»
598 «module.childNodes.treeSet(InstanceIdentifier.builder.toInstance())»
601 private def dispatch CharSequence tree(ChoiceNode node,InstanceIdentifier path) '''
602 «node.nodeName» (choice)
603 «casesTree(node.cases,path)»
606 def casesTree(Set<ChoiceCaseNode> nodes,InstanceIdentifier path) '''
611 «node.childNodes.treeSet(path)»
617 private def dispatch CharSequence tree(DataSchemaNode node,InstanceIdentifier path) '''
621 private def dispatch CharSequence tree(ListSchemaNode node,InstanceIdentifier path) '''
622 «val newPath = path.append(node)»
623 «localLink(newPath,node.nodeName)»
624 «node.childNodes.treeSet(newPath)»
627 private def dispatch CharSequence tree(ContainerSchemaNode node,InstanceIdentifier path) '''
628 «val newPath = path.append(node)»
629 «localLink(newPath,node.nodeName)»
630 «node.childNodes.treeSet(newPath)»
633 def CharSequence childNodes(Module module) '''
634 «val childNodes = module.childNodes»
635 «IF !childNodes.nullOrEmpty»
638 «childNodes.printChildren(3,InstanceIdentifier.builder().toInstance())»
642 def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
646 «IF node instanceof DataNodeContainer»
647 «val dataNode = node as DataNodeContainer»
649 «FOR usesNode : dataNode.uses»
654 «FOR typeDef : dataNode.typeDefinitions»
655 «typeDef.restrictions»
659 «FOR grouping : dataNode.groupings»
660 «grouping.printGrouping»
664 «FOR child : dataNode.childNodes»
665 «child.printSchemaNodeInfo»
673 def String typeAnchorLink(SchemaPath path, CharSequence text) {
675 val prefix = path.path.last.prefix
676 if(prefix == this.currentModule.prefix) {
677 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
678 } else if(!prefix.nullOrEmpty){
679 val String module = imports.get(prefix)
680 if(!module.nullOrEmpty) {
681 return '''«prefix»:«text»'''
682 //to enable external (import) links
683 //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
690 def CharSequence printBaseInfo(SchemaNode node) {
691 if(node instanceof LeafSchemaNode) {
692 val LeafSchemaNode leafNode = (node as LeafSchemaNode)
694 «printInfo(node, "leaf")»
695 «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
696 «listItem("units", leafNode.units)»
697 «listItem("default", leafNode.^default)»
700 } else if(node instanceof LeafListSchemaNode) {
701 val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
703 «printInfo(node, "leaf-list")»
704 «listItem("type", leafListNode.type?.QName.localName)»
707 } else if(node instanceof ListSchemaNode) {
708 val ListSchemaNode listNode = (node as ListSchemaNode)
710 «printInfo(node, "list")»
711 «FOR keyDef : listNode.keyDefinition»
712 «listItem("key definition", keyDef.localName)»
716 } else if(node instanceof ChoiceNode) {
717 val ChoiceNode choiceNode = (node as ChoiceNode)
719 «printInfo(node, "choice")»
720 «listItem("default case", choiceNode.defaultCase)»
721 «FOR caseNode : choiceNode.cases»
722 «caseNode.printSchemaNodeInfo»
726 } else if(node instanceof ChoiceCaseNode) {
728 «printInfo(node, "case")»
731 } else if(node instanceof ContainerSchemaNode) {
733 «printInfo(node, "container")»
736 } else if(node instanceof AnyXmlSchemaNode) {
738 «printInfo(node, "anyxml")»
744 def CharSequence printInfo(SchemaNode node, String nodeType) {
746 «IF node instanceof AugmentationTarget»
749 <li id="«node.path.schemaPathToId»">
750 «nodeType»: «node.QName.localName»
755 «strong(listItem(nodeType, node.QName.localName))»
758 «listItem("description", node.description)»
759 «listItem("reference", node.reference)»
760 «IF node instanceof DataSchemaNode»
761 «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
762 «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
763 «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
768 def CharSequence printUses(UsesNode usesNode) {
770 «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.path.last.localName)))»
774 «FOR sp : usesNode.refines.keySet»
775 «listItem("node name", usesNode.refines.get(sp).QName.localName)»
779 «FOR augment : usesNode.augmentations»
780 «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
786 def CharSequence printGrouping(GroupingDefinition grouping) {
788 «strong(listItem("grouping", grouping.QName.localName))»
792 def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {
793 val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
794 val leafNodes = nodes.filter(LeafSchemaNode)
795 val leafListNodes = nodes.filter(LeafListSchemaNode)
796 val choices = nodes.filter(ChoiceNode)
797 val cases = nodes.filter(ChoiceCaseNode)
798 val containers = nodes.filter(ContainerSchemaNode)
799 val lists = nodes.filter(ListSchemaNode)
801 «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
802 <h3>Direct children</h3>
804 «FOR childNode : anyxmlNodes»
805 «childNode.printShortInfo(level,path)»
807 «FOR childNode : leafNodes»
808 «childNode.printShortInfo(level,path)»
810 «FOR childNode : leafListNodes»
811 «childNode.printShortInfo(level,path)»
813 «FOR childNode : containers»
814 «childNode.printShortInfo(level,path)»
816 «FOR childNode : lists»
817 «childNode.printShortInfo(level,path)»
822 «IF !path.path.empty»
824 «nodes.xmlExample(path.path.last.nodeType,path)»
827 «FOR childNode : containers»
828 «childNode.printInfo(level,path)»
830 «FOR childNode : lists»
831 «childNode.printInfo(level,path)»
833 «FOR childNode : choices»
834 «childNode.printInfo(level,path)»
836 «FOR childNode : cases»
837 «childNode.printInfo(level,path)»
842 def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''
844 «xmlExampleTag(name,nodes.xmplExampleTags(path))»
848 def CharSequence xmplExampleTags(Set<DataSchemaNode> nodes, InstanceIdentifier identifier) '''
851 <!-- «node.QName.localName» -->
852 «node.asXmlExampleTag(identifier)»
857 private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, InstanceIdentifier identifier) '''
858 «node.QName.xmlExampleTag("...")»
861 private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, InstanceIdentifier identifier) '''
862 <!-- This node could appear multiple times -->
863 «node.QName.xmlExampleTag("...")»
866 private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, InstanceIdentifier identifier) '''
867 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
868 «node.QName.xmlExampleTag("...")»
872 private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, InstanceIdentifier identifier) '''
873 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
874 <!-- This node could appear multiple times -->
875 «node.QName.xmlExampleTag("...")»
879 private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, InstanceIdentifier identifier) '''
884 def xmlExampleTag(QName name, CharSequence data) {
885 return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
888 def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''
891 def header(int level,InstanceIdentifier name) '''
892 <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
893 «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
899 private def dispatch CharSequence printInfo(DataSchemaNode node, int level, InstanceIdentifier path) '''
900 «header(level+1,node.QName)»
903 private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) '''
904 «val newPath = path.append(node)»
905 «header(level,newPath)»
908 <dd>«newPath.asXmlPath»</dd>
909 <dt>Restconf path</dt>
910 <dd>«code(newPath.asRestconfPath)»</dd>
912 «node.childNodes.printChildren(level,newPath)»
915 private def dispatch CharSequence printInfo(ListSchemaNode node, int level, InstanceIdentifier path) '''
916 «val newPath = path.append(node)»
917 «header(level,newPath)»
920 <dd>«newPath.asXmlPath»</dd>
921 <dt>Restconf path</dt>
922 <dd>«code(newPath.asRestconfPath)»</dd>
924 «node.childNodes.printChildren(level,newPath)»
927 private def dispatch CharSequence printInfo(ChoiceNode node, int level, InstanceIdentifier path) '''
928 «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
929 «choiceCases.printChildren(level,path)»
932 private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, InstanceIdentifier path) '''
933 «node.childNodes.printChildren(level,path)»
938 def CharSequence printShortInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) {
939 val newPath = path.append(node);
941 <li>«strong(localLink(newPath,node.QName.localName))» (container)</li>
945 def CharSequence printShortInfo(ListSchemaNode node, int level, InstanceIdentifier path) {
946 val newPath = path.append(node);
948 <li>«strong(localLink(newPath,node.QName.localName))» (list)</li>
952 def CharSequence printShortInfo(AnyXmlSchemaNode node, int level, InstanceIdentifier path) {
954 <li>«strong((node.QName.localName))» (anyxml)</li>
958 def CharSequence printShortInfo(LeafSchemaNode node, int level, InstanceIdentifier path) {
960 <li>«strong((node.QName.localName))» (leaf)</li>
964 def CharSequence printShortInfo(LeafListSchemaNode node, int level, InstanceIdentifier path) {
966 <li>«strong((node.QName.localName))» (leaf-list)</li>
970 def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
972 <a href="#«anchor»">«text»</a>
976 def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''
977 <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
981 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ContainerSchemaNode node) {
982 val pathArguments = new ArrayList(identifier.path)
983 pathArguments.add(new NodeIdentifier(node.QName));
984 return new InstanceIdentifier(pathArguments);
987 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {
988 val pathArguments = new ArrayList(identifier.path)
989 val keyValues = new LinkedHashMap<QName,Object>();
990 if(node.keyDefinition !== null) {
991 for(definition : node.keyDefinition) {
992 keyValues.put(definition,new Object);
995 pathArguments.add(new NodeIdentifierWithPredicates(node.QName,keyValues));
996 return new InstanceIdentifier(pathArguments);
1000 def asXmlPath(InstanceIdentifier identifier) {
1004 def asRestconfPath(InstanceIdentifier identifier) {
1005 val it = new StringBuilder();
1006 append(currentModule.name)
1008 var previous = false;
1009 for(arg : identifier.path) {
1010 if(previous) append("/")
1011 append(arg.nodeType.localName);
1013 if(arg instanceof NodeIdentifierWithPredicates) {
1014 val nodeIdentifier = arg as NodeIdentifierWithPredicates;
1015 for(qname : nodeIdentifier.keyValues.keySet) {
1017 append(qname.localName)
1026 private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
1027 val List<QName> path = schemaPath.path
1028 val StringBuilder pathString = new StringBuilder()
1029 if (schemaPath.absolute) {
1030 pathString.append("/")
1033 val QName qname = path.get(0)
1034 var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision)
1037 if (parent instanceof DataNodeContainer) {
1038 var SchemaNode node = (parent as DataNodeContainer).getDataChildByName(name)
1039 if (node == null && (parent instanceof Module)) {
1040 val notifications = (parent as Module).notifications;
1041 for (notification : notifications) {
1042 if (notification.QName.equals(name)) {
1047 if (node == null && (parent instanceof Module)) {
1048 val rpcs = (parent as Module).rpcs;
1050 if (rpc.QName.equals(name)) {
1056 var String prefix = name.prefix
1057 var String moduleName
1058 if (prefix == null || "".equals(prefix) || prefix.equals(module.prefix)) {
1059 moduleName = module.name
1061 moduleName = imports.get(prefix)
1063 pathString.append(moduleName)
1064 pathString.append(":")
1065 pathString.append(name.localName)
1066 pathString.append("/")
1067 if(node instanceof ChoiceNode && dataNode !== null) {
1068 val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode];
1069 if(caseNode !== null) {
1070 pathString.append("(case)");
1071 pathString.append(caseNode.QName.localName);
1077 return pathString.toString;
1081 def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
1082 «IF childNodes !== null && !childNodes.empty»
1083 «FOR child : childNodes.values»
1084 «childInfo(child, childNodes)»
1089 def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
1090 «val String path = nodeSchemaPathToPath(node, childNodes)»
1101 private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, InstanceIdentifier path) '''
1102 «IF childNodes !== null && !childNodes.empty»
1104 «FOR child : childNodes»
1113 def listKeys(ListSchemaNode node) '''
1114 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
1117 private def CharSequence extensionInfo(ExtensionDefinition ext) '''
1120 «listItem("Argument", ext.argument)»
1124 private def dispatch CharSequence tree(Void obj, InstanceIdentifier path) '''
1129 /* #################### RESTRICTIONS #################### */
1130 private def restrictions(TypeDefinition<?> type) '''
1131 «type.baseType.toBaseStmt»
1136 private def dispatch toLength(TypeDefinition<?> type) {
1139 private def dispatch toLength(BinaryTypeDefinition type) '''
1140 «type.lengthConstraints.toLengthStmt»
1143 private def dispatch toLength(StringTypeDefinition type) '''
1144 «type.lengthConstraints.toLengthStmt»
1147 private def dispatch toLength(ExtendedType type) '''
1148 «type.lengthConstraints.toLengthStmt»
1151 private def dispatch toRange(TypeDefinition<?> type) {
1154 private def dispatch toRange(DecimalTypeDefinition type) '''
1155 «type.rangeConstraints.toRangeStmt»
1158 private def dispatch toRange(IntegerTypeDefinition type) '''
1159 «type.rangeConstraints.toRangeStmt»
1162 private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
1163 «type.rangeConstraints.toRangeStmt»
1166 private def dispatch toRange(ExtendedType type) '''
1167 «type.rangeConstraints.toRangeStmt»
1170 def toLengthStmt(Collection<LengthConstraint> lengths) '''
1171 «IF lengths != null && !lengths.empty»
1172 «listItem("Length restrictions:")»
1174 «FOR length : lengths»
1176 «IF length.min == length.max»
1179 <«length.min», «length.max»>
1187 def toRangeStmt(Collection<RangeConstraint> ranges) '''
1188 «IF ranges != null && !ranges.empty»
1189 «listItem("Range restrictions:")»
1191 «FOR range : ranges»
1193 «IF range.min == range.max»
1196 <«range.min», «range.max»>
1204 def toBaseStmt(TypeDefinition<?> baseType) '''
1205 «IF baseType != null»
1206 «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))»
1212 /* #################### UTILITY #################### */
1213 private def String strong(CharSequence str) '''<strong>«str»</strong>'''
1214 private def italic(CharSequence str) '''<i>«str»</i>'''
1216 def CharSequence descAndRefLi(SchemaNode node) '''
1217 «listItem("Description", node.description)»
1218 «listItem("Reference", node.reference)»
1221 def CharSequence descAndRef(SchemaNode node) '''
1223 «IF node.reference !== null»
1224 Reference «node.reference»
1228 private def listItem(String value) '''
1229 «IF value !== null && !value.empty»
1236 private def listItem(String name, String value) '''
1237 «IF value !== null && !value.empty»
1244 private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
1245 if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {
1249 val path = node.path.path
1250 val absolute = node.path.absolute;
1251 var StringBuilder result = new StringBuilder
1255 if (path !== null && !path.empty) {
1256 val List<QName> actual = new ArrayList()
1258 for (pathElement : path) {
1259 actual.add(pathElement)
1260 val DataSchemaNode nodeByPath = childNodes.get(new SchemaPath(actual, absolute))
1261 if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {
1262 result.append(pathElement.localName)
1263 if (i != path.size - 1) {
1270 return result.toString
1273 private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {
1274 for (node : source) {
1275 destination.put(node.path, node)
1276 if (node instanceof DataNodeContainer) {
1277 collectChildNodes((node as DataNodeContainer).childNodes, destination)
1279 if (node instanceof ChoiceNode) {
1280 val List<DataSchemaNode> choiceCases = new ArrayList()
1281 for (caseNode : (node as ChoiceNode).cases) {
1282 choiceCases.add(caseNode)
1284 collectChildNodes(choiceCases, destination)
1289 private def dispatch addedByInfo(SchemaNode node) '''
1292 private def dispatch addedByInfo(DataSchemaNode node) '''
1293 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
1296 private def dispatch isAddedBy(SchemaNode node) {
1300 private def dispatch isAddedBy(DataSchemaNode node) {
1301 if (node.augmenting || node.addedByUses) {
1308 private def dispatch nodeName(SchemaNode node) '''
1310 «italic(node.QName.localName)»«node.addedByInfo»
1312 «node.QName.localName»«node.addedByInfo»
1316 private def dispatch nodeName(ContainerSchemaNode node) '''
1318 «strong(italic(node.QName.localName))»«node.addedByInfo»
1320 «strong(node.QName.localName)»«node.addedByInfo»
1324 private def dispatch nodeName(ListSchemaNode node) '''
1326 «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
1328 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»