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.data.api.InstanceIdentifier
25 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates
26 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode
27 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
28 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
29 import org.opendaylight.yangtools.yang.model.api.ChoiceNode
30 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode
31 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
32 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
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.Module
39 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext
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.type.BinaryTypeDefinition
46 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
47 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
48 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
49 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
50 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
51 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
52 import org.opendaylight.yangtools.yang.model.util.ExtendedType
53 import org.slf4j.Logger
54 import org.slf4j.LoggerFactory
55 import org.sonatype.plexus.build.incremental.BuildContext
56 import org.sonatype.plexus.build.incremental.DefaultBuildContext
61 static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
62 static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
63 static val BuildContext CTX = new DefaultBuildContext();
64 var Module currentModule;
65 val Map<String, String> imports = new HashMap();
66 var SchemaContext ctx;
68 def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
72 for (module : modulesToGen) {
73 add(generateDocumentation(module, context));
78 def generateDocumentation(Module module, SchemaContext ctx) {
79 val destination = new File(path, '''«module.name».html''')
81 module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
83 val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))
84 val bw = new BufferedWriter(fw)
85 currentModule = module;
86 bw.append(generate(module, ctx));
89 } catch (IOException e) {
90 LOG.error(e.getMessage());
95 def generate(Module module, SchemaContext ctx) '''
99 <title>«module.name»</title>
107 def body(Module module, SchemaContext ctx) '''
110 «typeDefinitionsSummary(module)»
111 «identitiesSummary(module)»
112 «groupingsSummary(module)»
113 «augmentationsSummary(module, ctx)»
114 «objectsSummary(module)»
115 «notificationsSummary(module)»
116 «rpcsSummary(module)»
117 «extensionsSummary(module)»
118 «featuresSummary(module)»
120 «typeDefinitions(module)»
130 «notifications(module)»
132 «augmentations(module, ctx)»
143 private def typeDefinitionsSummary(Module module) {
144 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
145 if (typedefs.empty) {
150 <h3>Type Definitions Summary</h3>
156 «FOR typedef : typedefs»
159 «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))»
162 «typedef.description»
171 def typeDefinitions(Module module) {
172 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
173 if (typedefs.empty) {
177 <h2>Type Definitions</h2>
179 «FOR typedef : typedefs»
181 <h3 id="«typedef.QName.localName»">«typedef.QName.localName»</h3>
183 «typedef.descAndRefLi»
184 «typedef.restrictions»
192 private def identities(Module module) {
193 if (module.identities.empty) {
199 «FOR identity : module.identities»
201 <h3 id="«identity.QName.localName»">«identity.QName.localName»</h3>
203 «identity.descAndRefLi»
204 «IF identity.baseIdentity !== null»
205 «listItem("base", identity.baseIdentity.QName.localName)»
214 private def identitiesSummary(Module module) {
215 if (module.identities.empty) {
219 <h3>Identities Summary</h3>
225 «FOR identity : module.identities»
228 «anchorLink(identity.QName.localName, strong(identity.QName.localName))»
231 «identity.description»
239 private def groupings(Module module) {
240 if (module.groupings.empty) {
246 «FOR grouping : module.groupings»
248 <h3 id="«grouping.QName.localName»">«grouping.QName.localName»</h3>
250 «grouping.descAndRefLi»
251 «FOR childNode : grouping.childNodes»
252 «childNode.printSchemaNodeInfo»
261 private def groupingsSummary(Module module) {
262 if (module.groupings.empty) {
266 <h3>Groupings Summary</h3>
272 «FOR grouping : module.groupings»
275 «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))»
278 «grouping.description»
286 def dataStore(Module module) {
287 if (module.childNodes.empty) {
291 <h2>Datastore Structure</h2>
296 def augmentations(Module module, SchemaContext context) {
297 if (module.augmentations.empty) {
301 <h2>Augmentations</h2>
304 «FOR augment : module.augmentations»
306 <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
307 Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
308 «augment.description»
309 «IF augment.reference !== null»
310 Reference «augment.reference»
312 «IF augment.whenCondition !== null»
313 When «augment.whenCondition.toString»
315 «FOR childNode : augment.childNodes»
316 «childNode.printSchemaNodeInfo»
324 private def augmentationsSummary(Module module, SchemaContext context) {
325 if (module.augmentations.empty) {
329 <h3>Augmentations Summary</h3>
335 «FOR augment : module.augmentations»
338 «anchorLink(schemaPathToString(module, augment.targetPath, context, augment),
339 strong(schemaPathToString(module, augment.targetPath, context, augment)))»
342 «augment.description»
350 def notifications(Module module) {
351 val Set<NotificationDefinition> notificationdefs = module.notifications
352 if (notificationdefs.empty) {
357 <h2>Notifications</h2>
358 «FOR notificationdef : notificationdefs»
360 <h3 id="«notificationdef.path.schemaPathToId»">«notificationdef.nodeName»</h3>
361 «notificationdef.descAndRef»
362 «FOR childNode : notificationdef.childNodes»
363 «childNode.printSchemaNodeInfo»
369 private def notificationsSummary(Module module) {
370 if (module.notifications.empty) {
374 <h3>Notifications Summary</h3>
380 «FOR notification : module.notifications»
383 «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))»
386 «notification.description»
394 def rpcs(Module module) {
395 if (module.rpcs.empty) {
400 <h2>RPC Definitions</h2>
401 «FOR rpc : module.rpcs»
402 <h3 id="«rpc.QName.localName»">«rpc.nodeName»</h3>
405 «rpc.input.printSchemaNodeInfo»
406 «rpc.output.printSchemaNodeInfo»
413 private def rpcsSummary(Module module) {
414 if (module.rpcs.empty) {
418 <h3>RPCs Summary</h3>
424 «FOR rpc : module.rpcs»
427 «anchorLink(rpc.QName.localName, strong(rpc.QName.localName))»
438 def extensions(Module module) {
439 if (module.extensionSchemaNodes.empty) {
444 «FOR ext : module.extensionSchemaNodes»
446 <h3 id="«ext.QName.localName»">«ext.nodeName»</h3>
453 private def extensionsSummary(Module module) {
454 if (module.extensionSchemaNodes.empty) {
458 <h3>Extensions Summary</h3>
464 «FOR ext : module.extensionSchemaNodes»
467 «anchorLink(ext.QName.localName, strong(ext.QName.localName))»
478 def features(Module module) {
479 if (module.features.empty) {
486 «FOR feature : module.features»
488 <h3 id="«feature.QName.localName»">«feature.QName.localName»</h3>
490 «feature.descAndRefLi»
498 private def featuresSummary(Module module) {
499 if (module.features.empty) {
503 <h3>Features Summary</h3>
509 «FOR feature : module.features»
512 «anchorLink(feature.QName.localName, strong(feature.QName.localName))»
515 «feature.description»
523 private def objectsSummary(Module module) {
524 if (module.childNodes.empty) {
528 <h3>Child Nodes Summary</h3>
534 «FOR childNode : module.childNodes»
537 «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))»
540 «childNode.description»
548 def header(Module module)
550 <h1>«module.name»</h1>
552 <h2>Base Information</h2>
555 <td>«strong("prefix")»</td>
556 <td>«module.prefix»</td>
559 <td>«strong("namespace")»</td>
560 <td>«module.namespace»</td>
563 <td>«strong("revision")»</td>
564 <td>«REVISION_FORMAT.format(module.revision)»</td>
567 <td>«strong("description")»</td>
568 <td>«module.description»</td>
571 <td>«strong("yang-version")»</td>
572 <td>«module.yangVersion»</td>
575 «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
576 «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
582 def CharSequence schemaPathToId(SchemaPath path) {
584 return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»'''
588 def code(String string) '''<code>«string»</code>'''
590 def process(Module module) {
591 throw new UnsupportedOperationException("TODO: auto-generated method stub")
594 def CharSequence tree(Module module) '''
595 «strong(module.name)»
596 «module.childNodes.treeSet(InstanceIdentifier.builder.toInstance())»
599 private def dispatch CharSequence tree(ChoiceNode node,InstanceIdentifier path) '''
600 «node.nodeName» (choice)
601 «casesTree(node.cases,path)»
604 def casesTree(Set<ChoiceCaseNode> nodes,InstanceIdentifier path) '''
609 «node.childNodes.treeSet(path)»
615 private def dispatch CharSequence tree(DataSchemaNode node,InstanceIdentifier path) '''
619 private def dispatch CharSequence tree(ListSchemaNode node,InstanceIdentifier path) '''
620 «val newPath = path.append(node)»
621 «localLink(newPath,node.nodeName)»
622 «node.childNodes.treeSet(newPath)»
625 private def dispatch CharSequence tree(ContainerSchemaNode node,InstanceIdentifier path) '''
626 «val newPath = path.append(node)»
627 «localLink(newPath,node.nodeName)»
628 «node.childNodes.treeSet(newPath)»
631 def CharSequence childNodes(Module module) '''
632 «val childNodes = module.childNodes»
633 «IF !childNodes.nullOrEmpty»
636 «childNodes.printChildren(3,InstanceIdentifier.builder().toInstance())»
640 def CharSequence printSchemaNodeInfo(DataSchemaNode node) {
644 «IF node instanceof DataNodeContainer»
645 «val dataNode = node as DataNodeContainer»
647 «FOR usesNode : dataNode.uses»
652 «FOR typeDef : dataNode.typeDefinitions»
653 «typeDef.restrictions»
657 «FOR grouping : dataNode.groupings»
658 «grouping.printGrouping»
662 «FOR child : dataNode.childNodes»
663 «child.printSchemaNodeInfo»
671 def String typeAnchorLink(SchemaPath path, CharSequence text) {
673 val prefix = path.path.last.prefix
674 if(prefix == this.currentModule.prefix) {
675 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
676 } else if(!prefix.nullOrEmpty){
677 val String module = imports.get(prefix)
678 if(!module.nullOrEmpty) {
679 return '''«prefix»:«text»'''
680 //to enable external (import) links
681 //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
688 def CharSequence printBaseInfo(SchemaNode node) {
689 if(node instanceof LeafSchemaNode) {
690 val LeafSchemaNode leafNode = (node as LeafSchemaNode)
692 «printInfo(node, "leaf")»
693 «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
694 «listItem("units", leafNode.units)»
695 «listItem("default", leafNode.^default)»
698 } else if(node instanceof LeafListSchemaNode) {
699 val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
701 «printInfo(node, "leaf-list")»
702 «listItem("type", leafListNode.type?.QName.localName)»
705 } else if(node instanceof ListSchemaNode) {
706 val ListSchemaNode listNode = (node as ListSchemaNode)
708 «printInfo(node, "list")»
709 «FOR keyDef : listNode.keyDefinition»
710 «listItem("key definition", keyDef.localName)»
714 } else if(node instanceof ChoiceNode) {
715 val ChoiceNode choiceNode = (node as ChoiceNode)
717 «printInfo(node, "choice")»
718 «listItem("default case", choiceNode.defaultCase)»
719 «FOR caseNode : choiceNode.cases»
720 «caseNode.printSchemaNodeInfo»
724 } else if(node instanceof ChoiceCaseNode) {
726 «printInfo(node, "case")»
729 } else if(node instanceof ContainerSchemaNode) {
731 «printInfo(node, "container")»
734 } else if(node instanceof AnyXmlSchemaNode) {
736 «printInfo(node, "anyxml")»
742 def CharSequence printInfo(SchemaNode node, String nodeType) {
744 «IF node instanceof AugmentationTarget»
747 <li id="«node.path.schemaPathToId»">
748 «nodeType»: «node.QName.localName»
753 «strong(listItem(nodeType, node.QName.localName))»
756 «listItem("description", node.description)»
757 «listItem("reference", node.reference)»
758 «IF node instanceof DataSchemaNode»
759 «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
760 «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
761 «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
766 def CharSequence printUses(UsesNode usesNode) {
768 «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.path.last.localName)))»
772 «FOR sp : usesNode.refines.keySet»
773 «listItem("node name", usesNode.refines.get(sp).QName.localName)»
777 «FOR augment : usesNode.augmentations»
778 «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
784 def CharSequence printGrouping(GroupingDefinition grouping) {
786 «strong(listItem("grouping", grouping.QName.localName))»
790 def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {
791 val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
792 val leafNodes = nodes.filter(LeafSchemaNode)
793 val leafListNodes = nodes.filter(LeafListSchemaNode)
794 val choices = nodes.filter(ChoiceNode)
795 val cases = nodes.filter(ChoiceCaseNode)
796 val containers = nodes.filter(ContainerSchemaNode)
797 val lists = nodes.filter(ListSchemaNode)
799 «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
800 <h3>Direct children</h3>
802 «FOR childNode : anyxmlNodes»
803 «childNode.printShortInfo(level,path)»
805 «FOR childNode : leafNodes»
806 «childNode.printShortInfo(level,path)»
808 «FOR childNode : leafListNodes»
809 «childNode.printShortInfo(level,path)»
811 «FOR childNode : containers»
812 «childNode.printShortInfo(level,path)»
814 «FOR childNode : lists»
815 «childNode.printShortInfo(level,path)»
820 «IF !path.path.empty»
822 «nodes.xmlExample(path.path.last.nodeType,path)»
825 «FOR childNode : containers»
826 «childNode.printInfo(level,path)»
828 «FOR childNode : lists»
829 «childNode.printInfo(level,path)»
831 «FOR childNode : choices»
832 «childNode.printInfo(level,path)»
834 «FOR childNode : cases»
835 «childNode.printInfo(level,path)»
840 def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''
842 «xmlExampleTag(name,nodes.xmplExampleTags(path))»
846 def CharSequence xmplExampleTags(Set<DataSchemaNode> nodes, InstanceIdentifier identifier) '''
849 <!-- «node.QName.localName» -->
850 «node.asXmlExampleTag(identifier)»
855 private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, InstanceIdentifier identifier) '''
856 «node.QName.xmlExampleTag("...")»
859 private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, InstanceIdentifier identifier) '''
860 <!-- This node could appear multiple times -->
861 «node.QName.xmlExampleTag("...")»
864 private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, InstanceIdentifier identifier) '''
865 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
866 «node.QName.xmlExampleTag("...")»
870 private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, InstanceIdentifier identifier) '''
871 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
872 <!-- This node could appear multiple times -->
873 «node.QName.xmlExampleTag("...")»
877 private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, InstanceIdentifier identifier) '''
882 def xmlExampleTag(QName name, CharSequence data) {
883 return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
886 def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''
889 def header(int level,InstanceIdentifier name) '''
890 <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
891 «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
897 private def dispatch CharSequence printInfo(DataSchemaNode node, int level, InstanceIdentifier path) '''
898 «header(level+1,node.QName)»
901 private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) '''
902 «val newPath = path.append(node)»
903 «header(level,newPath)»
906 <dd>«newPath.asXmlPath»</dd>
907 <dt>Restconf path</dt>
908 <dd>«code(newPath.asRestconfPath)»</dd>
910 «node.childNodes.printChildren(level,newPath)»
913 private def dispatch CharSequence printInfo(ListSchemaNode node, int level, InstanceIdentifier path) '''
914 «val newPath = path.append(node)»
915 «header(level,newPath)»
918 <dd>«newPath.asXmlPath»</dd>
919 <dt>Restconf path</dt>
920 <dd>«code(newPath.asRestconfPath)»</dd>
922 «node.childNodes.printChildren(level,newPath)»
925 private def dispatch CharSequence printInfo(ChoiceNode node, int level, InstanceIdentifier path) '''
926 «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
927 «choiceCases.printChildren(level,path)»
930 private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, InstanceIdentifier path) '''
931 «node.childNodes.printChildren(level,path)»
936 def CharSequence printShortInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) {
937 val newPath = path.append(node);
939 <li>«strong(localLink(newPath,node.QName.localName))» (container)</li>
943 def CharSequence printShortInfo(ListSchemaNode node, int level, InstanceIdentifier path) {
944 val newPath = path.append(node);
946 <li>«strong(localLink(newPath,node.QName.localName))» (list)</li>
950 def CharSequence printShortInfo(AnyXmlSchemaNode node, int level, InstanceIdentifier path) {
952 <li>«strong((node.QName.localName))» (anyxml)</li>
956 def CharSequence printShortInfo(LeafSchemaNode node, int level, InstanceIdentifier path) {
958 <li>«strong((node.QName.localName))» (leaf)</li>
962 def CharSequence printShortInfo(LeafListSchemaNode node, int level, InstanceIdentifier path) {
964 <li>«strong((node.QName.localName))» (leaf-list)</li>
968 def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
970 <a href="#«anchor»">«text»</a>
974 def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''
975 <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
979 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ContainerSchemaNode node) {
980 return identifier.node(node.QName);
983 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {
984 val keyValues = new LinkedHashMap<QName,Object>();
985 if(node.keyDefinition !== null) {
986 for(definition : node.keyDefinition) {
987 keyValues.put(definition,new Object);
991 return identifier.node(new NodeIdentifierWithPredicates(node.QName, keyValues));
995 def asXmlPath(InstanceIdentifier identifier) {
999 def asRestconfPath(InstanceIdentifier identifier) {
1000 val it = new StringBuilder();
1001 append(currentModule.name)
1003 var previous = false;
1004 for(arg : identifier.path) {
1005 if(previous) append("/")
1006 append(arg.nodeType.localName);
1008 if(arg instanceof NodeIdentifierWithPredicates) {
1009 val nodeIdentifier = arg as NodeIdentifierWithPredicates;
1010 for(qname : nodeIdentifier.keyValues.keySet) {
1012 append(qname.localName)
1021 private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
1022 val List<QName> path = schemaPath.path
1023 val StringBuilder pathString = new StringBuilder()
1024 if (schemaPath.absolute) {
1025 pathString.append("/")
1028 val QName qname = path.get(0)
1029 var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision)
1032 if (parent instanceof DataNodeContainer) {
1033 var SchemaNode node = (parent as DataNodeContainer).getDataChildByName(name)
1034 if (node == null && (parent instanceof Module)) {
1035 val notifications = (parent as Module).notifications;
1036 for (notification : notifications) {
1037 if (notification.QName.equals(name)) {
1042 if (node == null && (parent instanceof Module)) {
1043 val rpcs = (parent as Module).rpcs;
1045 if (rpc.QName.equals(name)) {
1051 var String prefix = name.prefix
1052 var String moduleName
1053 if (prefix == null || "".equals(prefix) || prefix.equals(module.prefix)) {
1054 moduleName = module.name
1056 moduleName = imports.get(prefix)
1058 pathString.append(moduleName)
1059 pathString.append(":")
1060 pathString.append(name.localName)
1061 pathString.append("/")
1062 if(node instanceof ChoiceNode && dataNode !== null) {
1063 val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode];
1064 if(caseNode !== null) {
1065 pathString.append("(case)");
1066 pathString.append(caseNode.QName.localName);
1072 return pathString.toString;
1076 def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
1077 «IF childNodes !== null && !childNodes.empty»
1078 «FOR child : childNodes.values»
1079 «childInfo(child, childNodes)»
1084 def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
1085 «val String path = nodeSchemaPathToPath(node, childNodes)»
1096 private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, InstanceIdentifier path) '''
1097 «IF childNodes !== null && !childNodes.empty»
1099 «FOR child : childNodes»
1108 def listKeys(ListSchemaNode node) '''
1109 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
1112 private def CharSequence extensionInfo(ExtensionDefinition ext) '''
1115 «listItem("Argument", ext.argument)»
1119 private def dispatch CharSequence tree(Void obj, InstanceIdentifier path) '''
1124 /* #################### RESTRICTIONS #################### */
1125 private def restrictions(TypeDefinition<?> type) '''
1126 «type.baseType.toBaseStmt»
1131 private def dispatch toLength(TypeDefinition<?> type) {
1134 private def dispatch toLength(BinaryTypeDefinition type) '''
1135 «type.lengthConstraints.toLengthStmt»
1138 private def dispatch toLength(StringTypeDefinition type) '''
1139 «type.lengthConstraints.toLengthStmt»
1142 private def dispatch toLength(ExtendedType type) '''
1143 «type.lengthConstraints.toLengthStmt»
1146 private def dispatch toRange(TypeDefinition<?> type) {
1149 private def dispatch toRange(DecimalTypeDefinition type) '''
1150 «type.rangeConstraints.toRangeStmt»
1153 private def dispatch toRange(IntegerTypeDefinition type) '''
1154 «type.rangeConstraints.toRangeStmt»
1157 private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
1158 «type.rangeConstraints.toRangeStmt»
1161 private def dispatch toRange(ExtendedType type) '''
1162 «type.rangeConstraints.toRangeStmt»
1165 def toLengthStmt(Collection<LengthConstraint> lengths) '''
1166 «IF lengths != null && !lengths.empty»
1167 «listItem("Length restrictions:")»
1169 «FOR length : lengths»
1171 «IF length.min == length.max»
1174 <«length.min», «length.max»>
1182 def toRangeStmt(Collection<RangeConstraint> ranges) '''
1183 «IF ranges != null && !ranges.empty»
1184 «listItem("Range restrictions:")»
1186 «FOR range : ranges»
1188 «IF range.min == range.max»
1191 <«range.min», «range.max»>
1199 def toBaseStmt(TypeDefinition<?> baseType) '''
1200 «IF baseType != null»
1201 «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))»
1207 /* #################### UTILITY #################### */
1208 private def String strong(CharSequence str) '''<strong>«str»</strong>'''
1209 private def italic(CharSequence str) '''<i>«str»</i>'''
1211 def CharSequence descAndRefLi(SchemaNode node) '''
1212 «listItem("Description", node.description)»
1213 «listItem("Reference", node.reference)»
1216 def CharSequence descAndRef(SchemaNode node) '''
1218 «IF node.reference !== null»
1219 Reference «node.reference»
1223 private def listItem(String value) '''
1224 «IF value !== null && !value.empty»
1231 private def listItem(String name, String value) '''
1232 «IF value !== null && !value.empty»
1239 private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
1240 if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {
1244 val path = node.path.path
1245 val absolute = node.path.absolute;
1246 var StringBuilder result = new StringBuilder
1250 if (path !== null && !path.empty) {
1251 val List<QName> actual = new ArrayList()
1253 for (pathElement : path) {
1254 actual.add(pathElement)
1255 val DataSchemaNode nodeByPath = childNodes.get(SchemaPath.create(actual, absolute))
1256 if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {
1257 result.append(pathElement.localName)
1258 if (i != path.size - 1) {
1265 return result.toString
1268 private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {
1269 for (node : source) {
1270 destination.put(node.path, node)
1271 if (node instanceof DataNodeContainer) {
1272 collectChildNodes((node as DataNodeContainer).childNodes, destination)
1274 if (node instanceof ChoiceNode) {
1275 val List<DataSchemaNode> choiceCases = new ArrayList()
1276 for (caseNode : (node as ChoiceNode).cases) {
1277 choiceCases.add(caseNode)
1279 collectChildNodes(choiceCases, destination)
1284 private def dispatch addedByInfo(SchemaNode node) '''
1287 private def dispatch addedByInfo(DataSchemaNode node) '''
1288 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
1291 private def dispatch isAddedBy(SchemaNode node) {
1295 private def dispatch isAddedBy(DataSchemaNode node) {
1296 if (node.augmenting || node.addedByUses) {
1303 private def dispatch nodeName(SchemaNode node) '''
1305 «italic(node.QName.localName)»«node.addedByInfo»
1307 «node.QName.localName»«node.addedByInfo»
1311 private def dispatch nodeName(ContainerSchemaNode node) '''
1313 «strong(italic(node.QName.localName))»«node.addedByInfo»
1315 «strong(node.QName.localName)»«node.addedByInfo»
1319 private def dispatch nodeName(ListSchemaNode node) '''
1321 «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
1323 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»