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 «val Set<TypeDefinition<?>> typedefs = dataNode.typeDefinitions»
653 «FOR typeDef : typedefs»
654 «typeDef.restrictions»
658 «FOR grouping : dataNode.groupings»
659 «grouping.printGrouping»
663 «FOR child : dataNode.childNodes»
664 «child.printSchemaNodeInfo»
672 def String typeAnchorLink(SchemaPath path, CharSequence text) {
674 val prefix = path.path.last.prefix
675 if(prefix == this.currentModule.prefix) {
676 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
677 } else if(!prefix.nullOrEmpty){
678 val String module = imports.get(prefix)
679 if(!module.nullOrEmpty) {
680 return '''«prefix»:«text»'''
681 //to enable external (import) links
682 //return '''<a href="«module».html#«path.schemaPathToId»">«prefix»:«text»</a>'''
689 def CharSequence printBaseInfo(SchemaNode node) {
690 if(node instanceof LeafSchemaNode) {
691 val LeafSchemaNode leafNode = (node as LeafSchemaNode)
693 «printInfo(node, "leaf")»
694 «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))»
695 «listItem("units", leafNode.units)»
696 «listItem("default", leafNode.^default)»
699 } else if(node instanceof LeafListSchemaNode) {
700 val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode)
702 «printInfo(node, "leaf-list")»
703 «listItem("type", leafListNode.type?.QName.localName)»
706 } else if(node instanceof ListSchemaNode) {
707 val ListSchemaNode listNode = (node as ListSchemaNode)
709 «printInfo(node, "list")»
710 «FOR keyDef : listNode.keyDefinition»
711 «listItem("key definition", keyDef.localName)»
715 } else if(node instanceof ChoiceNode) {
716 val ChoiceNode choiceNode = (node as ChoiceNode)
718 «printInfo(node, "choice")»
719 «listItem("default case", choiceNode.defaultCase)»
720 «FOR caseNode : choiceNode.cases»
721 «caseNode.printSchemaNodeInfo»
725 } else if(node instanceof ChoiceCaseNode) {
727 «printInfo(node, "case")»
730 } else if(node instanceof ContainerSchemaNode) {
732 «printInfo(node, "container")»
735 } else if(node instanceof AnyXmlSchemaNode) {
737 «printInfo(node, "anyxml")»
743 def CharSequence printInfo(SchemaNode node, String nodeType) {
745 «IF node instanceof AugmentationTarget»
748 <li id="«node.path.schemaPathToId»">
749 «nodeType»: «node.QName.localName»
754 «strong(listItem(nodeType, node.QName.localName))»
757 «listItem("description", node.description)»
758 «listItem("reference", node.reference)»
759 «IF node instanceof DataSchemaNode»
760 «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)»
761 «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)»
762 «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)»
767 def CharSequence printUses(UsesNode usesNode) {
769 «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.pathTowardsRoot.iterator.next.localName)))»
773 «FOR sp : usesNode.refines.keySet»
774 «listItem("node name", usesNode.refines.get(sp).QName.localName)»
778 «FOR augment : usesNode.augmentations»
779 «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
785 def CharSequence printGrouping(GroupingDefinition grouping) {
787 «strong(listItem("grouping", grouping.QName.localName))»
791 def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {
792 val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
793 val leafNodes = nodes.filter(LeafSchemaNode)
794 val leafListNodes = nodes.filter(LeafListSchemaNode)
795 val choices = nodes.filter(ChoiceNode)
796 val cases = nodes.filter(ChoiceCaseNode)
797 val containers = nodes.filter(ContainerSchemaNode)
798 val lists = nodes.filter(ListSchemaNode)
800 «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»
801 <h3>Direct children</h3>
803 «FOR childNode : anyxmlNodes»
804 «childNode.printShortInfo(level,path)»
806 «FOR childNode : leafNodes»
807 «childNode.printShortInfo(level,path)»
809 «FOR childNode : leafListNodes»
810 «childNode.printShortInfo(level,path)»
812 «FOR childNode : containers»
813 «childNode.printShortInfo(level,path)»
815 «FOR childNode : lists»
816 «childNode.printShortInfo(level,path)»
821 «IF !path.path.empty»
823 «nodes.xmlExample(path.path.last.nodeType,path)»
826 «FOR childNode : containers»
827 «childNode.printInfo(level,path)»
829 «FOR childNode : lists»
830 «childNode.printInfo(level,path)»
832 «FOR childNode : choices»
833 «childNode.printInfo(level,path)»
835 «FOR childNode : cases»
836 «childNode.printInfo(level,path)»
841 def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''
843 «xmlExampleTag(name,nodes.xmplExampleTags(path))»
847 def CharSequence xmplExampleTags(Set<DataSchemaNode> nodes, InstanceIdentifier identifier) '''
850 <!-- «node.QName.localName» -->
851 «node.asXmlExampleTag(identifier)»
856 private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, InstanceIdentifier identifier) '''
857 «node.QName.xmlExampleTag("...")»
860 private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, InstanceIdentifier identifier) '''
861 <!-- This node could appear multiple times -->
862 «node.QName.xmlExampleTag("...")»
865 private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, InstanceIdentifier identifier) '''
866 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
867 «node.QName.xmlExampleTag("...")»
871 private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, InstanceIdentifier identifier) '''
872 <!-- See «localLink(identifier.append(node),"definition")» for child nodes. -->
873 <!-- This node could appear multiple times -->
874 «node.QName.xmlExampleTag("...")»
878 private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, InstanceIdentifier identifier) '''
883 def xmlExampleTag(QName name, CharSequence data) {
884 return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>'''
887 def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''
890 def header(int level,InstanceIdentifier name) '''
891 <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">
892 «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»
898 private def dispatch CharSequence printInfo(DataSchemaNode node, int level, InstanceIdentifier path) '''
899 «header(level+1,node.QName)»
902 private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) '''
903 «val newPath = path.append(node)»
904 «header(level,newPath)»
907 <dd>«newPath.asXmlPath»</dd>
908 <dt>Restconf path</dt>
909 <dd>«code(newPath.asRestconfPath)»</dd>
911 «node.childNodes.printChildren(level,newPath)»
914 private def dispatch CharSequence printInfo(ListSchemaNode node, int level, InstanceIdentifier path) '''
915 «val newPath = path.append(node)»
916 «header(level,newPath)»
919 <dd>«newPath.asXmlPath»</dd>
920 <dt>Restconf path</dt>
921 <dd>«code(newPath.asRestconfPath)»</dd>
923 «node.childNodes.printChildren(level,newPath)»
926 private def dispatch CharSequence printInfo(ChoiceNode node, int level, InstanceIdentifier path) '''
927 «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
928 «choiceCases.printChildren(level,path)»
931 private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, InstanceIdentifier path) '''
932 «node.childNodes.printChildren(level,path)»
937 def CharSequence printShortInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) {
938 val newPath = path.append(node);
940 <li>«strong(localLink(newPath,node.QName.localName))» (container)</li>
944 def CharSequence printShortInfo(ListSchemaNode node, int level, InstanceIdentifier path) {
945 val newPath = path.append(node);
947 <li>«strong(localLink(newPath,node.QName.localName))» (list)</li>
951 def CharSequence printShortInfo(AnyXmlSchemaNode node, int level, InstanceIdentifier path) {
953 <li>«strong((node.QName.localName))» (anyxml)</li>
957 def CharSequence printShortInfo(LeafSchemaNode node, int level, InstanceIdentifier path) {
959 <li>«strong((node.QName.localName))» (leaf)</li>
963 def CharSequence printShortInfo(LeafListSchemaNode node, int level, InstanceIdentifier path) {
965 <li>«strong((node.QName.localName))» (leaf-list)</li>
969 def CharSequence anchorLink(CharSequence anchor, CharSequence text) {
971 <a href="#«anchor»">«text»</a>
975 def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''
976 <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>
980 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ContainerSchemaNode node) {
981 return identifier.node(node.QName);
984 private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {
985 val keyValues = new LinkedHashMap<QName,Object>();
986 if(node.keyDefinition !== null) {
987 for(definition : node.keyDefinition) {
988 keyValues.put(definition,new Object);
992 return identifier.node(new NodeIdentifierWithPredicates(node.QName, keyValues));
996 def asXmlPath(InstanceIdentifier identifier) {
1000 def asRestconfPath(InstanceIdentifier identifier) {
1001 val it = new StringBuilder();
1002 append(currentModule.name)
1004 var previous = false;
1005 for(arg : identifier.path) {
1006 if(previous) append("/")
1007 append(arg.nodeType.localName);
1009 if(arg instanceof NodeIdentifierWithPredicates) {
1010 val nodeIdentifier = arg as NodeIdentifierWithPredicates;
1011 for(qname : nodeIdentifier.keyValues.keySet) {
1013 append(qname.localName)
1022 private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
1023 val List<QName> path = schemaPath.path
1024 val StringBuilder pathString = new StringBuilder()
1025 if (schemaPath.absolute) {
1026 pathString.append("/")
1029 val QName qname = path.get(0)
1030 var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision)
1033 if (parent instanceof DataNodeContainer) {
1034 var SchemaNode node = (parent as DataNodeContainer).getDataChildByName(name)
1035 if (node == null && (parent instanceof Module)) {
1036 val notifications = (parent as Module).notifications;
1037 for (notification : notifications) {
1038 if (notification.QName.equals(name)) {
1043 if (node == null && (parent instanceof Module)) {
1044 val rpcs = (parent as Module).rpcs;
1046 if (rpc.QName.equals(name)) {
1052 var String prefix = name.prefix
1053 var String moduleName
1054 if (prefix == null || "".equals(prefix) || prefix.equals(module.prefix)) {
1055 moduleName = module.name
1057 moduleName = imports.get(prefix)
1059 pathString.append(moduleName)
1060 pathString.append(":")
1061 pathString.append(name.localName)
1062 pathString.append("/")
1063 if(node instanceof ChoiceNode && dataNode !== null) {
1064 val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode];
1065 if(caseNode !== null) {
1066 pathString.append("(case)");
1067 pathString.append(caseNode.QName.localName);
1073 return pathString.toString;
1077 def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''
1078 «IF childNodes !== null && !childNodes.empty»
1079 «FOR child : childNodes.values»
1080 «childInfo(child, childNodes)»
1085 def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''
1086 «val String path = nodeSchemaPathToPath(node, childNodes)»
1097 private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, InstanceIdentifier path) '''
1098 «IF childNodes !== null && !childNodes.empty»
1100 «FOR child : childNodes»
1109 def listKeys(ListSchemaNode node) '''
1110 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
1113 private def CharSequence extensionInfo(ExtensionDefinition ext) '''
1116 «listItem("Argument", ext.argument)»
1120 private def dispatch CharSequence tree(Void obj, InstanceIdentifier path) '''
1125 /* #################### RESTRICTIONS #################### */
1126 private def restrictions(TypeDefinition<?> type) '''
1127 «type.baseType.toBaseStmt»
1132 private def dispatch toLength(TypeDefinition<?> type) {
1135 private def dispatch toLength(BinaryTypeDefinition type) '''
1136 «type.lengthConstraints.toLengthStmt»
1139 private def dispatch toLength(StringTypeDefinition type) '''
1140 «type.lengthConstraints.toLengthStmt»
1143 private def dispatch toLength(ExtendedType type) '''
1144 «type.lengthConstraints.toLengthStmt»
1147 private def dispatch toRange(TypeDefinition<?> type) {
1150 private def dispatch toRange(DecimalTypeDefinition type) '''
1151 «type.rangeConstraints.toRangeStmt»
1154 private def dispatch toRange(IntegerTypeDefinition type) '''
1155 «type.rangeConstraints.toRangeStmt»
1158 private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
1159 «type.rangeConstraints.toRangeStmt»
1162 private def dispatch toRange(ExtendedType type) '''
1163 «type.rangeConstraints.toRangeStmt»
1166 def toLengthStmt(Collection<LengthConstraint> lengths) '''
1167 «IF lengths != null && !lengths.empty»
1168 «listItem("Length restrictions:")»
1170 «FOR length : lengths»
1172 «IF length.min == length.max»
1175 <«length.min», «length.max»>
1183 def toRangeStmt(Collection<RangeConstraint> ranges) '''
1184 «IF ranges != null && !ranges.empty»
1185 «listItem("Range restrictions:")»
1187 «FOR range : ranges»
1189 «IF range.min == range.max»
1192 <«range.min», «range.max»>
1200 def toBaseStmt(TypeDefinition<?> baseType) '''
1201 «IF baseType != null»
1202 «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))»
1208 /* #################### UTILITY #################### */
1209 private def String strong(CharSequence str) '''<strong>«str»</strong>'''
1210 private def italic(CharSequence str) '''<i>«str»</i>'''
1212 def CharSequence descAndRefLi(SchemaNode node) '''
1213 «listItem("Description", node.description)»
1214 «listItem("Reference", node.reference)»
1217 def CharSequence descAndRef(SchemaNode node) '''
1219 «IF node.reference !== null»
1220 Reference «node.reference»
1224 private def listItem(String value) '''
1225 «IF value !== null && !value.empty»
1232 private def listItem(String name, String value) '''
1233 «IF value !== null && !value.empty»
1240 private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
1241 if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {
1245 val path = node.path.path
1246 val absolute = node.path.absolute;
1247 var StringBuilder result = new StringBuilder
1251 if (path !== null && !path.empty) {
1252 val List<QName> actual = new ArrayList()
1254 for (pathElement : path) {
1255 actual.add(pathElement)
1256 val DataSchemaNode nodeByPath = childNodes.get(SchemaPath.create(actual, absolute))
1257 if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {
1258 result.append(pathElement.localName)
1259 if (i != path.size - 1) {
1266 return result.toString
1269 private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {
1270 for (node : source) {
1271 destination.put(node.path, node)
1272 if (node instanceof DataNodeContainer) {
1273 collectChildNodes((node as DataNodeContainer).childNodes, destination)
1275 if (node instanceof ChoiceNode) {
1276 val List<DataSchemaNode> choiceCases = new ArrayList()
1277 for (caseNode : (node as ChoiceNode).cases) {
1278 choiceCases.add(caseNode)
1280 collectChildNodes(choiceCases, destination)
1285 private def dispatch addedByInfo(SchemaNode node) '''
1288 private def dispatch addedByInfo(DataSchemaNode node) '''
1289 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
1292 private def dispatch isAddedBy(SchemaNode node) {
1296 private def dispatch isAddedBy(DataSchemaNode node) {
1297 if (node.augmenting || node.addedByUses) {
1304 private def dispatch nodeName(SchemaNode node) '''
1306 «italic(node.QName.localName)»«node.addedByInfo»
1308 «node.QName.localName»«node.addedByInfo»
1312 private def dispatch nodeName(ContainerSchemaNode node) '''
1314 «strong(italic(node.QName.localName))»«node.addedByInfo»
1316 «strong(node.QName.localName)»«node.addedByInfo»
1320 private def dispatch nodeName(ListSchemaNode node) '''
1322 «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
1324 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»