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