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