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)»
91 «notifications(module)»
93 «augmentations(module)»
104 def typeDefinitions(Module module) {
105 val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
106 if (typedefs.empty) {
110 <h2>Type Definitions</h2>
112 «FOR typedef : typedefs»
114 «strong("typedef " + typedef.QName.localName)»
117 «typedef.restrictions»
125 private def identities(Module module) {
126 if (module.identities.empty) {
132 «FOR identity : module.identities»
134 «strong("identity " + identity.QName.localName)»
136 «identity.descAndRef»
137 «IF identity.baseIdentity != null»
138 «listItem("base", identity.baseIdentity.QName.localName)»
147 private def groupings(Module module) {
148 if (module.groupings.empty) {
154 «FOR grouping : module.groupings»
156 «strong("grouping " + grouping.QName.localName)»
158 «grouping.descAndRef»
166 def dataStore(Module module) {
167 if (module.childNodes.empty) {
171 <h2>Datastore Structure</h2>
176 def augmentations(Module module) {
177 if (module.augmentations.empty) {
181 <h2>Augmentations</h2>
184 «FOR augment : module.augmentations»
194 def notifications(Module module) {
195 val Set<NotificationDefinition> notificationdefs = module.notifications
196 if (notificationdefs.empty) {
200 <h2>Notifications</h2>
203 «FOR notificationdef : notificationdefs»
205 «notificationdef.nodeName»
206 «notificationdef.tree»
213 def rpcs(Module module) {
214 if (module.rpcs.empty) {
218 <h2>RPC Definitions</h2>
221 «FOR rpc : module.rpcs»
231 def extensions(Module module) {
232 if (module.extensionSchemaNodes.empty) {
239 «FOR ext : module.extensionSchemaNodes»
249 def features(Module module) {
250 if (module.features.empty) {
257 «FOR feature : module.features»
259 «strong("feature " + feature.QName.localName)»
269 def header(Module module) '''
270 <h1>«module.name»</h1>
272 <h2>Base Information</h2>
275 <dd>«pre(module.prefix)»</dd>
277 <dd>«pre(module.namespace.toString)»</dd>
279 <dd>«pre(REVISION_FORMAT.format(module.revision))»</dd>
281 «FOR imp : module.imports BEFORE "<dt>Imports</dt>" »
282 <dd>«pre(imp.prefix)» = «pre(imp.moduleName)»</dd>
287 def process(Module module) {
288 throw new UnsupportedOperationException("TODO: auto-generated method stub")
293 /* #################### TREE STRUCTURE #################### */
294 def dispatch CharSequence tree(Module module) '''
295 «strong("module " + module.name)»
296 «module.childNodes.tree»
299 def dispatch CharSequence tree(DataNodeContainer node) '''
300 «IF node instanceof SchemaNode»
301 «(node as SchemaNode).nodeName»
303 «node.childNodes.tree»
306 def dispatch CharSequence tree(DataSchemaNode node) '''
310 def dispatch CharSequence tree(ListSchemaNode node) '''
312 «node.childNodes.tree»
315 def dispatch CharSequence tree(Collection<DataSchemaNode> childNodes) '''
316 «IF childNodes !== null && !childNodes.empty»
318 «FOR child : childNodes»
327 def listKeys(ListSchemaNode node) '''
328 [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»]
331 def dispatch CharSequence tree(AugmentationSchema augment) '''
333 «listItem(augment.description)»
334 «listItem("Reference", augment.reference)»
335 «IF augment.whenCondition !== null»
336 «listItem("When", augment.whenCondition.toString)»
339 Path «augment.targetPath.path.pathToTree»
343 «augment.childNodes.tree»
348 def dispatch CharSequence tree(NotificationDefinition notification) '''
350 «notification.descAndRef»
353 «notification.childNodes.tree»
358 def dispatch CharSequence tree(RpcDefinition rpc) '''
370 def dispatch CharSequence tree(ExtensionDefinition ext) '''
373 «listItem("Argument", ext.argument)»
379 /* #################### RESTRICTIONS #################### */
380 private def restrictions(TypeDefinition<?> type) '''
385 def dispatch toLength(TypeDefinition<?> type) {
388 def dispatch toLength(BinaryTypeDefinition type) '''
389 «type.lengthConstraints.toLengthStmt»
392 def dispatch toLength(StringTypeDefinition type) '''
393 «type.lengthConstraints.toLengthStmt»
396 def dispatch toLength(ExtendedType type) '''
397 «type.lengthConstraints.toLengthStmt»
400 def dispatch toRange(TypeDefinition<?> type) {
403 def dispatch toRange(DecimalTypeDefinition type) '''
404 «type.rangeConstraints.toRangeStmt»
407 def dispatch toRange(IntegerTypeDefinition type) '''
408 «type.rangeConstraints.toRangeStmt»
411 def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
412 «type.rangeConstraints.toRangeStmt»
415 def dispatch toRange(ExtendedType type) '''
416 «type.rangeConstraints.toRangeStmt»
419 def toLengthStmt(Collection<LengthConstraint> lengths) '''
420 «IF lengths != null && !lengths.empty»
421 «listItem("Length restrictions")»
423 «FOR length : lengths»
425 «IF length.min == length.max»
428 <«length.min», «length.max»>
436 def toRangeStmt(Collection<RangeConstraint> ranges) '''
437 «IF ranges != null && !ranges.empty»
438 «listItem("Range restrictions")»
442 «IF range.min == range.max»
445 <«range.min», «range.max»>
455 /* #################### UTILITY #################### */
456 private def strong(String str) '''<strong>«str»</strong>'''
457 private def italic(String str) '''<i>«str»</i>'''
458 private def pre(String str) '''<pre>«str»</pre>'''
460 def CharSequence descAndRef(SchemaNode node) '''
461 «listItem(node.description)»
462 «listItem("Reference", node.reference)»
465 private def listItem(String value) '''
466 «IF value !== null && !value.empty»
473 private def listItem(String name, String value) '''
474 «IF value !== null && !value.empty»
486 private def CharSequence pathToTree(List<QName> path) '''
487 «IF path !== null && !path.empty»
489 «FOR pathElement : path»
491 «pathElement.namespace» «pathElement.localName»
498 def dispatch addedByInfo(SchemaNode node) '''
501 def dispatch addedByInfo(DataSchemaNode node) '''
502 «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
505 def dispatch isAddedBy(SchemaNode node) {
509 def dispatch isAddedBy(DataSchemaNode node) {
510 if (node.augmenting || node.addedByUses) {
517 def dispatch nodeName(SchemaNode node) '''
519 «italic(node.QName.localName)»«node.addedByInfo»
521 «strong(node.QName.localName)»«node.addedByInfo»
525 def dispatch nodeName(ListSchemaNode node) '''
527 «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
529 «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»