Merge "Updated union builder template to throw an exception in getDefaultInstance...
[mdsal.git] / code-generator / maven-sal-api-gen-plugin / src / main / java / org / opendaylight / yangtools / yang / unified / doc / generator / GeneratorImpl.xtend
1 package org.opendaylight.yangtools.yang.unified.doc.generator\r
2 \r
3 import org.opendaylight.yangtools.yang.model.api.SchemaContext\r
4 import java.io.File\r
5 import java.util.Set\r
6 import org.opendaylight.yangtools.yang.model.api.Module\r
7 import java.io.IOException\r
8 import java.util.HashSet\r
9 import java.io.BufferedWriter\r
10 import java.io.OutputStream;\r
11 import java.io.OutputStreamWriter;\r
12 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode\r
13 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode\r
14 import org.opendaylight.yangtools.yang.model.api.TypeDefinition\r
15 import org.opendaylight.yangtools.yang.model.api.SchemaNode\r
16 import org.opendaylight.yangtools.yang.model.util.ExtendedType\r
17 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition\r
18 import java.text.SimpleDateFormat\r
19 import java.util.Collection\r
20 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint\r
21 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition\r
22 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition\r
23 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint\r
24 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition\r
25 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition\r
26 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition\r
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer\r
28 import org.slf4j.LoggerFactory\r
29 import org.slf4j.Logger\r
30 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema\r
31 import java.util.List\r
32 import org.opendaylight.yangtools.yang.common.QName\r
33 import org.opendaylight.yangtools.yang.model.api.RpcDefinition\r
34 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition\r
35 import java.util.ArrayList\r
36 import java.util.Map\r
37 import org.opendaylight.yangtools.yang.model.api.SchemaPath\r
38 \r
39 import org.sonatype.plexus.build.incremental.BuildContext;\r
40 import org.sonatype.plexus.build.incremental.DefaultBuildContext;\r
41 \r
42 import org.opendaylight.yangtools.yang.model.api.ChoiceNode\r
43 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode\r
44 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode\r
45 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier\r
46 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates\r
47 import java.util.LinkedHashMap\r
48 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier\r
49 import com.google.common.collect.FluentIterable\r
50 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode\r
51 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode\r
52 import java.net.URLEncoder\r
53 import javax.swing.text.StyledEditorKit.ForegroundAction\r
54 \r
55 class GeneratorImpl {\r
56 \r
57     File path\r
58     static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")\r
59     static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)\r
60     static val BuildContext CTX = new DefaultBuildContext();\r
61     var Module currentModule;\r
62 \r
63 \r
64     def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {\r
65         path = targetPath;\r
66         path.mkdirs();\r
67         val it = new HashSet;\r
68         for (module : modulesToGen) {\r
69             add(module.generateDocumentation());\r
70         }\r
71         return it;\r
72     }\r
73 \r
74     def generateDocumentation(Module module) {\r
75         val destination = new File(path, '''«module.name».html''')\r
76         try {\r
77             val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination))\r
78             val bw = new BufferedWriter(fw)\r
79             currentModule = module;\r
80             bw.append(module.generate);\r
81             bw.close();\r
82             fw.close();\r
83         } catch (IOException e) {\r
84             LOG.error(e.getMessage());\r
85         }\r
86         return destination;\r
87     }\r
88 \r
89     def generate(Module module) '''\r
90         <!DOCTYPE html>\r
91         <html lang="en">\r
92           <head>\r
93             <title>«module.name»</title>\r
94           </head>\r
95           <body>\r
96             «module.body»\r
97           </body>\r
98         </html>\r
99     '''\r
100 \r
101     def body(Module module) '''\r
102         «header(module)»\r
103 \r
104         «typeDefinitions(module)»\r
105 \r
106         «identities(module)»\r
107 \r
108         «groupings(module)»\r
109 \r
110         «dataStore(module)»\r
111 \r
112         «childNodes(module)»\r
113 \r
114         «notifications(module)»\r
115 \r
116         «augmentations(module)»\r
117 \r
118         «rpcs(module)»\r
119 \r
120         «extensions(module)»\r
121 \r
122         «features(module)»\r
123 \r
124     '''\r
125 \r
126 \r
127     def typeDefinitions(Module module) {\r
128         val Set<TypeDefinition<?>> typedefs = module.typeDefinitions\r
129         if (typedefs.empty) {\r
130             return '';\r
131         }\r
132         return '''\r
133             <h2>Type Definitions</h2>\r
134             <ul>\r
135             «FOR typedef : typedefs»\r
136                 <li>\r
137                     «strong("typedef " + typedef.QName.localName)»\r
138                     <ul>\r
139                     «typedef.descAndRef»\r
140                     «typedef.restrictions»\r
141                     </ul>\r
142                 </li>\r
143             «ENDFOR»\r
144             </ul>\r
145         '''\r
146     }\r
147 \r
148     private def identities(Module module) {\r
149         if (module.identities.empty) {\r
150             return '';\r
151         }\r
152         return '''\r
153             <h2>Identities</h2>\r
154             <ul>\r
155             «FOR identity : module.identities»\r
156                 <li>\r
157                     «strong("identity " + identity.QName.localName)»\r
158                     <ul>\r
159                     «identity.descAndRef»\r
160                     «IF identity.baseIdentity != null»\r
161                         «listItem("base", identity.baseIdentity.QName.localName)»\r
162                     «ENDIF»\r
163                     </ul>\r
164                 </li>\r
165             «ENDFOR»\r
166             </ul>\r
167         '''\r
168     }\r
169 \r
170     private def groupings(Module module) {\r
171         if (module.groupings.empty) {\r
172             return '';\r
173         }\r
174         return '''\r
175             <h2>Groupings</h2>\r
176             <ul>\r
177             «FOR grouping : module.groupings»\r
178                 <li>\r
179                     «strong("grouping " + grouping.QName.localName)»\r
180                     <ul>\r
181                         «grouping.descAndRef»\r
182                     </ul>\r
183                 </li>\r
184             «ENDFOR»\r
185             </ul>\r
186         '''\r
187     }\r
188 \r
189     def dataStore(Module module) {\r
190         if (module.childNodes.empty) {\r
191             return '';\r
192         }\r
193         return '''\r
194             <h2>Datastore Structure</h2>\r
195             «tree(module)»\r
196         '''\r
197     }\r
198 \r
199     def augmentations(Module module) {\r
200         if (module.augmentations.empty) {\r
201             return '';\r
202         }\r
203         return '''\r
204             <h2>Augmentations</h2>\r
205 \r
206             <ul>\r
207             «FOR augment : module.augmentations»\r
208                 <li>\r
209                     augment\r
210                     «augment.augmentationInfo(InstanceIdentifier.builder().toInstance())»\r
211                     «augment.childNodes.printChildren(2,InstanceIdentifier.builder().toInstance())»\r
212                 </li>\r
213             «ENDFOR»\r
214             </ul>\r
215         '''\r
216     }\r
217 \r
218     def notifications(Module module) {\r
219         val Set<NotificationDefinition> notificationdefs = module.notifications\r
220         if (notificationdefs.empty) {\r
221             return '';\r
222         }\r
223         \r
224         return '''\r
225             <h2>Notifications</h2>\r
226             «FOR notificationdef : notificationdefs»\r
227                 \r
228                 <h3>«notificationdef.nodeName»</h3>\r
229                     «notificationdef.notificationInfo(InstanceIdentifier.builder().node(notificationdef.QName).toInstance())»\r
230             «ENDFOR»\r
231         '''\r
232     }\r
233 \r
234     def rpcs(Module module) {\r
235         if (module.rpcs.empty) {\r
236             return '';\r
237         }\r
238         \r
239         return '''\r
240             <h2>RPC Definitions</h2>\r
241             «FOR rpc : module.rpcs»\r
242                 <h3>«rpc.nodeName»</h3>\r
243                     «rpc.rpcInfo(InstanceIdentifier.builder().node(rpc.QName).toInstance())»\r
244             «ENDFOR»\r
245             </ul>\r
246         '''\r
247     }\r
248 \r
249     def extensions(Module module) {\r
250         if (module.extensionSchemaNodes.empty) {\r
251             return '';\r
252         }\r
253         return '''\r
254             <h2>Extensions</h2>\r
255             «FOR ext : module.extensionSchemaNodes»\r
256                 <li>\r
257                     <h3>«ext.nodeName»</h3>\r
258                 </li>\r
259             «ENDFOR»\r
260         '''\r
261     }\r
262 \r
263     def features(Module module) {\r
264         if (module.features.empty) {\r
265             return '';\r
266         }\r
267         return '''\r
268             <h2>Features</h2>\r
269 \r
270             <ul>\r
271             «FOR feature : module.features»\r
272                 <li>\r
273                     «strong("feature " + feature.QName.localName)»\r
274                     <ul>\r
275                         «feature.descAndRef»\r
276                     </ul>\r
277                 </li>\r
278             «ENDFOR»\r
279             </ul>\r
280         '''\r
281     }\r
282 \r
283     def header(Module module) '''\r
284         <h1>«module.name»</h1>\r
285         \r
286         <h2>Base Information</h2>\r
287         <dl>\r
288             <dt>Prefix</dt>\r
289             <dd>«pre(module.prefix)»</dd>\r
290             <dt>Namespace</dt>\r
291             <dd>«pre(module.namespace.toString)»</dd>\r
292             <dt>Revision</dt>\r
293             <dd>«pre(REVISION_FORMAT.format(module.revision))»</dd>\r
294             \r
295             «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »\r
296                 <dd>«code(imp.prefix)» = «code(imp.moduleName)»</dd>\r
297             «ENDFOR»\r
298         </dl>\r
299     '''\r
300     \r
301     def code(String string) '''<code>«string»</code>'''\r
302         \r
303     def process(Module module) {\r
304         throw new UnsupportedOperationException("TODO: auto-generated method stub")\r
305     }\r
306 \r
307     def CharSequence tree(Module module) '''\r
308         «strong("module " + module.name)»\r
309         «module.childNodes.treeSet(InstanceIdentifier.builder.toInstance())»\r
310     '''\r
311     \r
312     private def dispatch CharSequence tree(ChoiceNode node,InstanceIdentifier path) '''\r
313         «node.nodeName» (choice)\r
314         «casesTree(node.cases,path)»\r
315     '''\r
316     \r
317     def casesTree(Set<ChoiceCaseNode> nodes,InstanceIdentifier path) '''\r
318         <ul>\r
319         «FOR node : nodes»\r
320             <li>\r
321             «node.nodeName»\r
322             «node.childNodes.treeSet(path)»\r
323             </li>\r
324         «ENDFOR»\r
325         </ul>\r
326     '''\r
327 \r
328     private def dispatch CharSequence tree(DataSchemaNode node,InstanceIdentifier path) '''\r
329         «node.nodeName»\r
330     '''\r
331 \r
332     private def dispatch CharSequence tree(ListSchemaNode node,InstanceIdentifier path) '''\r
333         «val newPath = path.append(node)»\r
334         «localLink(newPath,node.nodeName)»\r
335         «node.childNodes.treeSet(newPath)»\r
336     '''\r
337     \r
338     private def dispatch CharSequence tree(ContainerSchemaNode node,InstanceIdentifier path) '''\r
339         «val newPath = path.append(node)»\r
340         «localLink(newPath,node.nodeName)»\r
341         «node.childNodes.treeSet(newPath)»\r
342     '''\r
343 \r
344     def CharSequence childNodes(Module module) '''\r
345         «val childNodes = module.childNodes»\r
346         «IF childNodes !== null && !childNodes.empty»\r
347             <h2>Child nodes</h2>\r
348 \r
349             «childNodes.printChildren(2,InstanceIdentifier.builder().toInstance())»\r
350         «ENDIF»\r
351     '''\r
352     \r
353     def CharSequence printChildren(Set<DataSchemaNode> nodes, int level, InstanceIdentifier path) {\r
354     val leafNodes = nodes.filter(LeafSchemaNode)\r
355     val leafListNodes = nodes.filter(LeafListSchemaNode)\r
356     val choices = nodes.filter(ChoiceNode)\r
357     val cases = nodes.filter(ChoiceCaseNode)\r
358     val containers = nodes.filter(ContainerSchemaNode)\r
359     val lists = nodes.filter(ListSchemaNode)\r
360     return '''\r
361         <h3>Direct children</h3>\r
362         <ul>\r
363         «FOR childNode : leafNodes»\r
364             «childNode.printShortInfo(level,path)»\r
365         «ENDFOR»\r
366         «FOR childNode : leafListNodes»\r
367             «childNode.printShortInfo(level,path)»\r
368         «ENDFOR»\r
369         «FOR childNode : containers»\r
370             «childNode.printShortInfo(level,path)»\r
371         «ENDFOR»\r
372         «FOR childNode : lists»\r
373             «childNode.printShortInfo(level,path)»\r
374         «ENDFOR»\r
375         </ul>\r
376         \r
377         «IF !path.path.empty»\r
378         <h3>XML example</h3>\r
379         «nodes.xmlExample(path.path.last.nodeType,path)»\r
380         </h3>\r
381         «ENDIF»\r
382         «FOR childNode : containers»\r
383             «childNode.printInfo(level,path)»\r
384         «ENDFOR»\r
385         «FOR childNode : lists»\r
386             «childNode.printInfo(level,path)»\r
387         «ENDFOR»\r
388         «FOR childNode : choices»\r
389             «childNode.printInfo(level,path)»\r
390         «ENDFOR»\r
391         «FOR childNode : cases»\r
392             «childNode.printInfo(level,path)»\r
393         «ENDFOR»\r
394         \r
395     '''\r
396     }\r
397     \r
398     def CharSequence xmlExample(Set<DataSchemaNode> nodes, QName name,InstanceIdentifier path) '''\r
399     <pre>\r
400         «xmlExampleTag(name,nodes.xmplExampleTags(path))»\r
401     </pre>\r
402     '''\r
403     \r
404     def CharSequence xmplExampleTags(Set<DataSchemaNode> nodes, InstanceIdentifier identifier) '''\r
405         <!-- Child nodes -->\r
406         «FOR node : nodes»\r
407         <!-- «node.QName.localName» -->\r
408             «node.asXmlExampleTag(identifier)»\r
409         «ENDFOR»\r
410         \r
411     '''\r
412     \r
413     private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, InstanceIdentifier identifier) '''\r
414         «node.QName.xmlExampleTag("...")»\r
415     '''\r
416     \r
417     private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, InstanceIdentifier identifier) '''\r
418         &lt!-- This node could appear multiple times --&gt\r
419         «node.QName.xmlExampleTag("...")»\r
420     '''\r
421     \r
422     private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, InstanceIdentifier identifier) '''\r
423         &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt\r
424         «node.QName.xmlExampleTag("...")»\r
425     '''\r
426     \r
427     \r
428     private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, InstanceIdentifier identifier) '''\r
429         &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt\r
430         &lt!-- This node could appear multiple times --&gt\r
431         «node.QName.xmlExampleTag("...")»\r
432     '''\r
433     \r
434     \r
435     private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, InstanceIdentifier identifier) '''\r
436         <!-- noop -->\r
437     '''\r
438     \r
439     \r
440     def xmlExampleTag(QName name, CharSequence data) {\r
441         return '''&lt;«name.localName» xmlns="«name.namespace»"&gt;«data»&lt;/«name.localName»&gt;'''\r
442     }\r
443     \r
444     private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) '''\r
445         «val newPath = path.append(node)»\r
446         «header(level,newPath)»\r
447         <dl>\r
448           <dt>XML Path</dt>\r
449           <dd>«newPath.asXmlPath»</dd>\r
450           <dt>Restconf path</dt>\r
451           <dd>«code(newPath.asRestconfPath)»</dd>\r
452         </dl>\r
453         «node.childNodes.printChildren(level,newPath)»\r
454     '''\r
455     \r
456     def header(int level,QName name) '''<h«level»>«name.localName»</h«level»>'''\r
457     \r
458     \r
459     def header(int level,InstanceIdentifier name) \r
460         '''\r
461         <h«level» id="«FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">\r
462             «FOR cmp : name.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»\r
463         </h«level»>'''\r
464     \r
465     \r
466     private def dispatch CharSequence printInfo(ListSchemaNode node, int level, InstanceIdentifier path) '''\r
467         «val newPath = path.append(node)»\r
468         «header(level,newPath)»\r
469         <dl>\r
470           <dt>XML Path</dt>\r
471           <dd>«newPath.asXmlPath»</dd>\r
472           <dt>Restconf path</dt>\r
473           <dd>«code(newPath.asRestconfPath)»</dd>\r
474         </dl>\r
475         «node.childNodes.printChildren(level,newPath)»\r
476     '''\r
477 \r
478     private def dispatch CharSequence printInfo(ChoiceNode node, int level, InstanceIdentifier path) '''\r
479         «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»\r
480         «choiceCases.printChildren(level,path)»\r
481     '''\r
482 \r
483     private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, InstanceIdentifier path) '''\r
484         «node.childNodes.printChildren(level,path)»\r
485     '''\r
486 \r
487     def CharSequence printShortInfo(ContainerSchemaNode node, int level, InstanceIdentifier path) {\r
488         val newPath = path.append(node);\r
489         return '''\r
490             <li>«strong(localLink(newPath,node.QName.localName))» (container)</li>\r
491         '''\r
492     }\r
493     \r
494     def CharSequence printShortInfo(ListSchemaNode node, int level, InstanceIdentifier path) {\r
495         val newPath = path.append(node);\r
496         return '''\r
497             <li>«strong(localLink(newPath,node.QName.localName))» (list)</li>\r
498         '''\r
499     }\r
500     \r
501     def CharSequence printShortInfo(LeafSchemaNode node, int level, InstanceIdentifier path) {\r
502         return '''\r
503             <li>«strong((node.QName.localName))» (leaf)</li>\r
504         '''\r
505     }\r
506     \r
507     def CharSequence printShortInfo(LeafListSchemaNode node, int level, InstanceIdentifier path) {\r
508         return '''\r
509             <li>«strong((node.QName.localName))» (leaf-list)</li>\r
510         '''\r
511     }\r
512 \r
513     def CharSequence localLink(InstanceIdentifier identifier, CharSequence text) '''\r
514         <a href="#«FOR cmp : identifier.path SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR»">«text»</a>\r
515     '''\r
516     \r
517     \r
518     private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ContainerSchemaNode node) {\r
519         val pathArguments = new ArrayList(identifier.path)\r
520         pathArguments.add(new NodeIdentifier(node.QName));\r
521         return new InstanceIdentifier(pathArguments);\r
522     }\r
523     \r
524     private def dispatch InstanceIdentifier append(InstanceIdentifier identifier, ListSchemaNode node) {\r
525         val pathArguments = new ArrayList(identifier.path)\r
526         val keyValues = new LinkedHashMap<QName,Object>();\r
527         if(node.keyDefinition != null) {\r
528             for(definition : node.keyDefinition) {\r
529                 keyValues.put(definition,new Object);\r
530             }\r
531         }\r
532         pathArguments.add(new NodeIdentifierWithPredicates(node.QName,keyValues));\r
533         return new InstanceIdentifier(pathArguments);\r
534     }\r
535     \r
536     \r
537     def asXmlPath(InstanceIdentifier identifier) {\r
538         return "";\r
539     }\r
540     \r
541     def asRestconfPath(InstanceIdentifier identifier) {\r
542         val it = new StringBuilder();\r
543         append(currentModule.name)\r
544         append(":")\r
545         var previous = false;\r
546         for(arg : identifier.path) {\r
547             if(previous) append("/")\r
548             append(arg.nodeType.localName);\r
549             previous = true;\r
550             if(arg instanceof NodeIdentifierWithPredicates) {\r
551                 val nodeIdentifier = arg as NodeIdentifierWithPredicates;\r
552                 for(qname : nodeIdentifier.keyValues.keySet) {\r
553                     append("/{");\r
554                     append(qname.localName)\r
555                     append("}")\r
556                 }\r
557             }\r
558         }\r
559         \r
560         return it.toString;\r
561     }\r
562     \r
563     \r
564     private def dispatch CharSequence printInfo(DataSchemaNode node, int level, InstanceIdentifier path) '''\r
565         «header(level+1,node.QName)»\r
566     '''\r
567     \r
568 \r
569 \r
570 \r
571 \r
572     def CharSequence childNodesInfoTree(Map<SchemaPath, DataSchemaNode> childNodes) '''\r
573         «IF childNodes !== null && !childNodes.empty»\r
574             «FOR child : childNodes.values»\r
575                 «childInfo(child, childNodes)»\r
576             «ENDFOR»\r
577         «ENDIF»\r
578     '''\r
579 \r
580     def CharSequence childInfo(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) '''\r
581         «val String path = nodeSchemaPathToPath(node, childNodes)»\r
582         «IF path != null»\r
583             «code(path)»\r
584                 «IF node !== null»\r
585                 <ul>\r
586                 «node.descAndRef»\r
587                 </ul>\r
588             «ENDIF»\r
589         «ENDIF»\r
590     '''\r
591 \r
592     private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, InstanceIdentifier path) '''\r
593         «IF childNodes !== null && !childNodes.empty»\r
594             <ul>\r
595             «FOR child : childNodes»\r
596                 <li>\r
597                     «child.tree(path)»\r
598                 </li>\r
599             «ENDFOR»\r
600             </ul>\r
601         «ENDIF»\r
602     '''\r
603 \r
604     def listKeys(ListSchemaNode node) '''\r
605         [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]\r
606     '''\r
607 \r
608     private def CharSequence augmentationInfo(AugmentationSchema augment, InstanceIdentifier path) '''\r
609         <ul>\r
610             «listItem(augment.description)»\r
611             «listItem("Reference", augment.reference)»\r
612             «IF augment.whenCondition !== null»\r
613                 «listItem("When", augment.whenCondition.toString)»\r
614             «ENDIF»\r
615             <li>\r
616                 Path «augment.targetPath.path.pathToTree»\r
617             </li>\r
618             <li>\r
619                 Child nodes\r
620                 «augment.childNodes.treeSet(path)»\r
621             </li>\r
622         </ul>\r
623     '''\r
624 \r
625     private def CharSequence notificationInfo(NotificationDefinition notification,InstanceIdentifier path) '''\r
626         <ul>\r
627             «notification.descAndRef»\r
628             <li>\r
629                 Child nodes\r
630                 «notification.childNodes.treeSet(path)»\r
631             </li>\r
632         </ul>\r
633     '''\r
634 \r
635     private def CharSequence rpcInfo(RpcDefinition rpc,InstanceIdentifier path) '''\r
636         <ul>\r
637             «rpc.descAndRef»\r
638             <li>\r
639                 «rpc.input.tree(path)»\r
640             </li>\r
641             <li>\r
642                 «rpc.output.tree(path)»\r
643             </li>\r
644         </ul>\r
645     '''\r
646 \r
647     private def CharSequence extensionInfo(ExtensionDefinition ext, InstanceIdentifier path) '''\r
648         <ul>\r
649             «ext.descAndRef»\r
650             «listItem("Argument", ext.argument)»\r
651         </ul>\r
652     '''\r
653 \r
654     private def dispatch CharSequence tree(Void obj, InstanceIdentifier path) '''\r
655     '''\r
656 \r
657 \r
658 \r
659     /* #################### RESTRICTIONS #################### */\r
660     private def restrictions(TypeDefinition<?> type) '''\r
661         «type.toLength»\r
662         «type.toRange»\r
663     '''\r
664 \r
665     private def dispatch toLength(TypeDefinition<?> type) {\r
666     }\r
667 \r
668     private def dispatch toLength(BinaryTypeDefinition type) '''\r
669         «type.lengthConstraints.toLengthStmt»\r
670     '''\r
671 \r
672     private def dispatch toLength(StringTypeDefinition type) '''\r
673         «type.lengthConstraints.toLengthStmt»\r
674     '''\r
675 \r
676     private def dispatch toLength(ExtendedType type) '''\r
677         «type.lengthConstraints.toLengthStmt»\r
678     '''\r
679 \r
680     private def dispatch toRange(TypeDefinition<?> type) {\r
681     }\r
682 \r
683     private def dispatch toRange(DecimalTypeDefinition type) '''\r
684         «type.rangeConstraints.toRangeStmt»\r
685     '''\r
686 \r
687     private def dispatch toRange(IntegerTypeDefinition type) '''\r
688         «type.rangeConstraints.toRangeStmt»\r
689     '''\r
690 \r
691     private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''\r
692         «type.rangeConstraints.toRangeStmt»\r
693     '''\r
694 \r
695     private def dispatch toRange(ExtendedType type) '''\r
696         «type.rangeConstraints.toRangeStmt»\r
697     '''\r
698 \r
699     def toLengthStmt(Collection<LengthConstraint> lengths) '''\r
700         «IF lengths != null && !lengths.empty»\r
701             «listItem("Length restrictions")»\r
702             <ul>\r
703             «FOR length : lengths»\r
704                 <li>\r
705                 «IF length.min == length.max»\r
706                     «length.min»\r
707                 «ELSE»\r
708                     &lt;«length.min», «length.max»&gt;\r
709                 «ENDIF»\r
710                 </li>\r
711             «ENDFOR»\r
712             </ul>\r
713         «ENDIF»\r
714     '''\r
715 \r
716     def toRangeStmt(Collection<RangeConstraint> ranges) '''\r
717         «IF ranges != null && !ranges.empty»\r
718             «listItem("Range restrictions")»\r
719             <ul>\r
720             «FOR range : ranges»\r
721                 <li>\r
722                 «IF range.min == range.max»\r
723                     «range.min»\r
724                 «ELSE»\r
725                     &lt;«range.min», «range.max»&gt;\r
726                 «ENDIF»\r
727                 </li>\r
728             «ENDFOR»\r
729             </ul>\r
730         «ENDIF»\r
731     '''\r
732 \r
733 \r
734 \r
735     /* #################### UTILITY #################### */\r
736     private def String strong(CharSequence str) '''<strong>«str»</strong>'''\r
737     private def italic(CharSequence str) '''<i>«str»</i>'''\r
738     private def pre(CharSequence str) '''<pre>«str»</pre>'''\r
739 \r
740     def CharSequence descAndRef(SchemaNode node) '''\r
741         «listItem(node.description)»\r
742         «listItem("Reference", node.reference)»\r
743     '''\r
744 \r
745     private def listItem(String value) '''\r
746         «IF value !== null && !value.empty»\r
747             <li>\r
748                 «value»\r
749             </li>\r
750         «ENDIF»\r
751     '''\r
752 \r
753     private def listItem(String name, String value) '''\r
754         «IF value !== null && !value.empty»\r
755             <li>\r
756                 «name»\r
757                 <ul>\r
758                     <li>\r
759                         «value»\r
760                     </li>\r
761                 </ul>\r
762             </li>\r
763         «ENDIF»\r
764     '''\r
765 \r
766     private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {\r
767         if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) {\r
768             return null\r
769         }\r
770 \r
771         val path = node.path.path\r
772         val absolute = node.path.absolute;\r
773         var StringBuilder result = new StringBuilder\r
774         if (absolute) {\r
775             result.append("/")\r
776         }\r
777         if (path !== null && !path.empty) {\r
778             val List<QName> actual = new ArrayList()\r
779             var i = 0;\r
780             for (pathElement : path) {\r
781                 actual.add(pathElement)\r
782                 val DataSchemaNode nodeByPath = childNodes.get(new SchemaPath(actual, absolute)) \r
783                 if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) {\r
784                     result.append(pathElement.localName)\r
785                     if (i != path.size - 1) {\r
786                         result.append("/")\r
787                     }\r
788                 }\r
789                 i = i + 1\r
790             }\r
791         }\r
792         return result.toString\r
793     }\r
794 \r
795     private def void collectChildNodes(Collection<DataSchemaNode> source, Map<SchemaPath, DataSchemaNode> destination) {\r
796         for (node : source) {\r
797             destination.put(node.path, node)\r
798             if (node instanceof DataNodeContainer) {\r
799                 collectChildNodes((node as DataNodeContainer).childNodes, destination)\r
800             }\r
801             if (node instanceof ChoiceNode) {\r
802                 val List<DataSchemaNode> choiceCases = new ArrayList()\r
803                 for (caseNode : (node as ChoiceNode).cases) {\r
804                     choiceCases.add(caseNode)\r
805                 }\r
806                 collectChildNodes(choiceCases, destination)\r
807             }\r
808         }\r
809     }\r
810 \r
811     private def CharSequence pathToTree(List<QName> path) '''\r
812         «IF path !== null && !path.empty»\r
813             <ul>\r
814             «FOR pathElement : path»\r
815                 <li>\r
816                     «pathElement.namespace» «pathElement.localName»\r
817                 </li>\r
818             «ENDFOR»\r
819             </ul>\r
820         «ENDIF»\r
821     '''\r
822 \r
823     private def dispatch addedByInfo(SchemaNode node) '''\r
824     '''\r
825 \r
826     private def dispatch addedByInfo(DataSchemaNode node) '''\r
827         «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»\r
828     '''\r
829 \r
830     private def dispatch isAddedBy(SchemaNode node) {\r
831         return false;\r
832     }\r
833 \r
834     private def dispatch isAddedBy(DataSchemaNode node) {\r
835         if (node.augmenting || node.addedByUses) {\r
836             return true\r
837         } else {\r
838             return false;\r
839         }\r
840     }\r
841 \r
842     private def dispatch nodeName(SchemaNode node) '''\r
843         «IF node.isAddedBy»\r
844             «italic(node.QName.localName)»«node.addedByInfo»\r
845         «ELSE»\r
846             «node.QName.localName»«node.addedByInfo»\r
847         «ENDIF»\r
848     '''\r
849     \r
850     private def dispatch nodeName(ContainerSchemaNode node) '''\r
851         «IF node.isAddedBy»\r
852             «strong(italic(node.QName.localName))»«node.addedByInfo»\r
853         «ELSE»\r
854             «strong(node.QName.localName)»«node.addedByInfo»\r
855         «ENDIF»\r
856     '''\r
857 \r
858     private def dispatch nodeName(ListSchemaNode node) '''\r
859         «IF node.isAddedBy»\r
860             «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»\r
861         «ELSE»\r
862             «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»\r
863         «ENDIF»\r
864     '''\r
865 \r
866 }\r