1 package org.opendaylight.yangtools.yang.unified.doc.generator
3 import org.opendaylight.yangtools.yang.model.api.SchemaContext
6 import org.opendaylight.yangtools.yang.model.api.Module
7 import java.io.IOException
8 import java.util.HashSet
9 import java.io.FileWriter
10 import java.io.BufferedWriter
11 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode
12 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode
13 import org.opendaylight.yangtools.yang.model.api.TypeDefinition
14 import org.opendaylight.yangtools.yang.model.api.SchemaNode
15 import org.opendaylight.yangtools.yang.model.util.ExtendedType
16 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition
17 import java.text.SimpleDateFormat
18 import java.util.Collection
19 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
20 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition
21 import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition
22 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint
23 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition
24 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition
25 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
26 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer
27 import org.slf4j.LoggerFactory
28 import org.slf4j.Logger
29 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema
31 import org.opendaylight.yangtools.yang.common.QName
32 import org.opendaylight.yangtools.yang.model.api.RpcDefinition
33 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition
38 static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd")
39 static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl)
42 def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
46 for (module : modulesToGen) {
47 add(module.generateDocumentation());
52 def generateDocumentation(Module module) {
53 val destination = new File(path, '''«module.name».html''')
55 val fw = new FileWriter(destination)
56 destination.createNewFile();
57 val bw = new BufferedWriter(fw)
59 bw.append(module.generate);
62 } catch (IOException e) {
63 LOG.error(e.getMessage());
68 def generate(Module module) '''
72 <title>«module.name»</title>
80 def body(Module module) '''
83 «typeDefinitions(module)»
89 «notifications(module)»
91 «augmentations(module)»
100 def typeDefinitions(Module module) {
101 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
102 if (typedefs.empty) {
106 <h2>Type Definitions</h2>
109 «FOR typedef : typedefs»
110 «typeDefinition(typedef)»
115 private def CharSequence typeDefinition(TypeDefinition<?> type) '''
121 def groupings(Module module) {
122 if (module.groupings.empty) {
127 «list(module.groupings)»
129 «FOR grouping : module.groupings»
130 «headerAndBody(grouping)»
135 def dataStore(Module module) {
136 if (module.childNodes.empty) {
140 <h2>Datastore Structure</h2>
145 def augmentations(Module module) {
146 if (module.augmentations.empty) {
150 <h2>Augmentations</h2>
153 «FOR augment : module.augmentations»
163 def notifications(Module module) {
164 val Set<NotificationDefinition> notificationdefs = module.notifications
165 if (notificationdefs.empty) {
169 <h2>Notifications</h2>
172 «FOR notificationdef : notificationdefs»
174 «notificationdef.nodeName»
175 «notificationdef.tree»
182 def rpcs(Module module) {
183 if (module.rpcs.empty) {
187 <h2>RPC Definitions</h2>
190 «FOR rpc : module.rpcs»
200 def extensions(Module module) {
201 if (module.extensionSchemaNodes.empty) {
208 «FOR ext : module.extensionSchemaNodes»
218 def CharSequence headerAndBody(SchemaNode node) '''
223 def header(SchemaNode type) '''
224 <h3>«type.QName.localName»</h3>
227 def body(SchemaNode definition) '''
229 «paragraphs(definition.description)»
231 «definition.reference»
235 def list(Set<? extends SchemaNode> definitions) '''
237 «FOR nodeDef : definitions»
238 <li>«nodeDef.QName.localName»</li>
243 def header(Module module) '''
244 <h1>«module.name»</h1>
246 <h2>Base Information</h2>
249 <dd><pre>«module.prefix»</pre></dd>
251 <dd><pre>«module.namespace»</pre></dd>
253 <dd>«REVISION_FORMAT.format(module.revision)»</dd>
255 «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »
256 <dd>«pre(imp.prefix)» = «pre(imp.moduleName)»</dd>
262 def process(Module module) {
263 throw new UnsupportedOperationException("TODO: auto-generated method stub")
268 /* #################### TREE STRUCTURE #################### */
269 def dispatch CharSequence tree(Module module) '''
270 «strong("module " + module.name)»
271 «module.childNodes.childrenToTree»
274 def dispatch CharSequence tree(DataNodeContainer node) '''
275 «IF node instanceof SchemaNode»
276 «(node as SchemaNode).nodeName»
278 «node.childNodes.childrenToTree»
281 def dispatch CharSequence tree(DataSchemaNode node) '''
285 def dispatch CharSequence tree(ListSchemaNode node) '''
287 «node.childNodes.childrenToTree»
290 private def CharSequence childrenToTree(Collection<DataSchemaNode> childNodes) '''
291 «IF childNodes !== null && !childNodes.empty»
293 «FOR child : childNodes»
302 def listKeys(ListSchemaNode node) '''
303 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
306 def dispatch CharSequence tree(AugmentationSchema augment) '''
308 «listItem("Description", augment.description)»
309 «listItem("Reference", augment.reference)»
310 «IF augment.whenCondition !== null»
311 «listItem("When", augment.whenCondition.toString)»
314 Path «augment.targetPath.path.pathToTree»
318 «augment.childNodes.childrenToTree»
323 private def CharSequence pathToTree(List<QName> path) '''
324 «IF path !== null && !path.empty»
326 «FOR pathElement : path»
328 «pathElement.namespace» «pathElement.localName»
335 def dispatch CharSequence tree(NotificationDefinition notification) '''
337 «listItem("Description", notification.description)»
338 «listItem("Reference", notification.reference)»
341 «notification.childNodes.childrenToTree»
346 def dispatch CharSequence tree(RpcDefinition rpc) '''
348 «listItem("Description", rpc.description)»
349 «listItem("Reference", rpc.reference)»
359 def dispatch CharSequence tree(ExtensionDefinition ext) '''
361 «listItem("Description", ext.description)»
362 «listItem("Reference", ext.reference)»
363 «listItem("Argument", ext.argument)»
368 /* #################### RESTRICTIONS #################### */
369 private def restrictions(TypeDefinition<?> type) '''
374 def dispatch toLength(TypeDefinition<?> type) {
377 def dispatch toLength(BinaryTypeDefinition type) '''
378 «type.lengthConstraints.toLengthStmt»
381 def dispatch toLength(StringTypeDefinition type) '''
382 «type.lengthConstraints.toLengthStmt»
385 def dispatch toLength(ExtendedType type) '''
386 «type.lengthConstraints.toLengthStmt»
389 def dispatch toRange(TypeDefinition<?> type) {
392 def dispatch toRange(DecimalTypeDefinition type) '''
393 «type.rangeConstraints.toRangeStmt»
396 def dispatch toRange(IntegerTypeDefinition type) '''
397 «type.rangeConstraints.toRangeStmt»
400 def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
401 «type.rangeConstraints.toRangeStmt»
404 def dispatch toRange(ExtendedType type) '''
405 «type.rangeConstraints.toRangeStmt»
408 def toLengthStmt(Collection<LengthConstraint> lengths) '''
409 «IF lengths != null && !lengths.empty»
410 «strong("Length restrictions")»
412 «FOR length : lengths»
414 «IF length.min == length.max»
417 <«length.min», «length.max»>
425 def toRangeStmt(Collection<RangeConstraint> ranges) '''
426 «IF ranges != null && !ranges.empty»
427 «strong("Range restrictions")»
431 «IF range.min == range.max»
434 <«range.min», «range.max»>
444 /* #################### UTILITY #################### */
445 def strong(String str) '''
446 <strong>«str»</strong>
449 def italic(String str) '''
453 def pre(String string) '''<pre>«string»</pre>'''
455 def paragraphs(String body) '''
459 def listItem(String name, String value) '''
460 «IF value !== null && !value.empty»
472 def dispatch addedByInfo(SchemaNode node) '''
475 def dispatch addedByInfo(DataSchemaNode node) '''
476 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
479 def dispatch isAddedBy(SchemaNode node) {
483 def dispatch isAddedBy(DataSchemaNode node) {
484 if (node.augmenting || node.addedByUses) {
491 def nodeName(SchemaNode node) '''
493 «italic(node.QName.localName)»«node.addedByInfo»
495 «strong(node.QName.localName)»«node.addedByInfo»
499 def nodeName(ListSchemaNode node) '''
501 «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
503 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»