package org.opendaylight.yangtools.yang.unified.doc.generator import org.opendaylight.yangtools.yang.model.api.SchemaContext import java.io.File import java.util.Set import org.opendaylight.yangtools.yang.model.api.Module import java.io.IOException import java.util.HashSet import java.io.FileWriter import java.io.BufferedWriter import org.opendaylight.yangtools.yang.model.api.DataSchemaNode import org.opendaylight.yangtools.yang.model.api.ListSchemaNode import org.opendaylight.yangtools.yang.model.api.TypeDefinition import org.opendaylight.yangtools.yang.model.api.SchemaNode import org.opendaylight.yangtools.yang.model.util.ExtendedType import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition import java.text.SimpleDateFormat import java.util.Collection import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition import org.opendaylight.yangtools.yang.model.api.NotificationDefinition import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.slf4j.LoggerFactory import org.slf4j.Logger import org.opendaylight.yangtools.yang.model.api.AugmentationSchema import java.util.List import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.model.api.RpcDefinition import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition import java.util.ArrayList import java.util.Map import org.opendaylight.yangtools.yang.model.api.SchemaPath import java.util.LinkedHashMap import org.opendaylight.yangtools.yang.model.api.ChoiceNode import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode class GeneratorImpl { File path static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd") static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl) def generate(SchemaContext context, File targetPath, Set modulesToGen) throws IOException { path = targetPath; path.mkdirs(); val it = new HashSet; for (module : modulesToGen) { add(module.generateDocumentation()); } return it; } def generateDocumentation(Module module) { val destination = new File(path, '''«module.name».html''') try { val fw = new FileWriter(destination) destination.createNewFile(); val bw = new BufferedWriter(fw) bw.append(module.generate); bw.close(); fw.close(); } catch (IOException e) { LOG.error(e.getMessage()); } return destination; } def generate(Module module) ''' «module.name» «module.body» ''' def body(Module module) ''' «header(module)» «typeDefinitions(module)» «identities(module)» «groupings(module)» «childNodes(module)» «dataStore(module)» «notifications(module)» «augmentations(module)» «rpcs(module)» «extensions(module)» «features(module)» ''' def typeDefinitions(Module module) { val Set> typedefs = module.typeDefinitions if (typedefs.empty) { return ''; } return '''

Type Definitions

''' } private def identities(Module module) { if (module.identities.empty) { return ''; } return '''

Identities

''' } private def groupings(Module module) { if (module.groupings.empty) { return ''; } return '''

Groupings

''' } def dataStore(Module module) { if (module.childNodes.empty) { return ''; } return '''

Datastore Structure

«tree(module)» ''' } def augmentations(Module module) { if (module.augmentations.empty) { return ''; } return '''

Augmentations

''' } def notifications(Module module) { val Set notificationdefs = module.notifications if (notificationdefs.empty) { return ''; } return '''

Notifications

    «FOR notificationdef : notificationdefs»
  • «notificationdef.nodeName» «notificationdef.tree»
  • «ENDFOR»
''' } def rpcs(Module module) { if (module.rpcs.empty) { return ''; } return '''

RPC Definitions

    «FOR rpc : module.rpcs»
  • «rpc.nodeName» «rpc.tree»
  • «ENDFOR»
''' } def extensions(Module module) { if (module.extensionSchemaNodes.empty) { return ''; } return '''

Extensions

    «FOR ext : module.extensionSchemaNodes»
  • «ext.nodeName» «ext.tree»
  • «ENDFOR»
''' } def features(Module module) { if (module.features.empty) { return ''; } return '''

Features

    «FOR feature : module.features»
  • «strong("feature " + feature.QName.localName)»
      «feature.descAndRef»
  • «ENDFOR»
''' } def header(Module module) '''

«module.name»

Base Information

Prefix
«pre(module.prefix)»
Namespace
«pre(module.namespace.toString)»
Revision
«pre(REVISION_FORMAT.format(module.revision))»
«FOR imp : module.imports BEFORE "
Imports
" »
«pre(imp.prefix)» = «pre(imp.moduleName)»
«ENDFOR»
''' def process(Module module) { throw new UnsupportedOperationException("TODO: auto-generated method stub") } /* #################### TREE STRUCTURE #################### */ def dispatch CharSequence tree(Module module) ''' «strong("module " + module.name)» «module.childNodes.tree» ''' def dispatch CharSequence tree(DataNodeContainer node) ''' «IF node instanceof SchemaNode» «(node as SchemaNode).nodeName» «ENDIF» «node.childNodes.tree» ''' def dispatch CharSequence tree(DataSchemaNode node) ''' «node.nodeName» ''' def dispatch CharSequence tree(ListSchemaNode node) ''' «node.nodeName» «node.childNodes.tree» ''' def CharSequence childNodes(Module module) ''' «val Map childNodes = new LinkedHashMap()» «collectChildNodes(module.childNodes, childNodes)» «IF childNodes !== null && !childNodes.empty»

Child nodes

«childNodes.childNodesInfoTree» «ENDIF» ''' def CharSequence childNodesInfoTree(Map childNodes) ''' «IF childNodes !== null && !childNodes.empty»
    «FOR child : childNodes.values» «childInfo(child, childNodes)» «ENDFOR»
«ENDIF» ''' def CharSequence childInfo(DataSchemaNode node, Map childNodes) ''' «val String path = nodeSchemaPathToPath(node, childNodes)» «IF path != null» «listItem(strong(path))» «IF node !== null»
    «node.descAndRef»
«ENDIF» «ENDIF» ''' def dispatch CharSequence tree(Collection childNodes) ''' «IF childNodes !== null && !childNodes.empty»
    «FOR child : childNodes»
  • «child.tree»
  • «ENDFOR»
«ENDIF» ''' def listKeys(ListSchemaNode node) ''' [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»] ''' def dispatch CharSequence tree(AugmentationSchema augment) '''
    «listItem(augment.description)» «listItem("Reference", augment.reference)» «IF augment.whenCondition !== null» «listItem("When", augment.whenCondition.toString)» «ENDIF»
  • Path «augment.targetPath.path.pathToTree»
  • Child nodes «augment.childNodes.tree»
''' def dispatch CharSequence tree(NotificationDefinition notification) '''
    «notification.descAndRef»
  • Child nodes «notification.childNodes.tree»
''' def dispatch CharSequence tree(RpcDefinition rpc) '''
    «rpc.descAndRef»
  • «rpc.input.tree»
  • «rpc.output.tree»
''' def dispatch CharSequence tree(ExtensionDefinition ext) '''
    «ext.descAndRef» «listItem("Argument", ext.argument)»
''' /* #################### RESTRICTIONS #################### */ private def restrictions(TypeDefinition type) ''' «type.toLength» «type.toRange» ''' def dispatch toLength(TypeDefinition type) { } def dispatch toLength(BinaryTypeDefinition type) ''' «type.lengthConstraints.toLengthStmt» ''' def dispatch toLength(StringTypeDefinition type) ''' «type.lengthConstraints.toLengthStmt» ''' def dispatch toLength(ExtendedType type) ''' «type.lengthConstraints.toLengthStmt» ''' def dispatch toRange(TypeDefinition type) { } def dispatch toRange(DecimalTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' def dispatch toRange(IntegerTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' def dispatch toRange(UnsignedIntegerTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' def dispatch toRange(ExtendedType type) ''' «type.rangeConstraints.toRangeStmt» ''' def toLengthStmt(Collection lengths) ''' «IF lengths != null && !lengths.empty» «listItem("Length restrictions")»
    «FOR length : lengths»
  • «IF length.min == length.max» «length.min» «ELSE» <«length.min», «length.max»> «ENDIF»
  • «ENDFOR»
«ENDIF» ''' def toRangeStmt(Collection ranges) ''' «IF ranges != null && !ranges.empty» «listItem("Range restrictions")»
    «FOR range : ranges»
  • «IF range.min == range.max» «range.min» «ELSE» <«range.min», «range.max»> «ENDIF»
  • «ENDFOR»
«ENDIF» ''' /* #################### UTILITY #################### */ private def String strong(String str) '''«str»''' private def italic(String str) '''«str»''' private def pre(String str) '''
«str»
''' def CharSequence descAndRef(SchemaNode node) ''' «listItem(node.description)» «listItem("Reference", node.reference)» ''' private def listItem(String value) ''' «IF value !== null && !value.empty»
  • «value»
  • «ENDIF» ''' private def listItem(String name, String value) ''' «IF value !== null && !value.empty»
  • «name»
    • «value»
  • «ENDIF» ''' private def String nodeSchemaPathToPath(DataSchemaNode node, Map childNodes) { if (node instanceof ChoiceNode || node instanceof ChoiceCaseNode) { return null } val path = node.path.path val absolute = node.path.absolute; var StringBuilder result = new StringBuilder if (absolute) { result.append("/") } if (path !== null && !path.empty) { val List actual = new ArrayList() var i = 0; for (pathElement : path) { actual.add(pathElement) val DataSchemaNode nodeByPath = childNodes.get(new SchemaPath(actual, absolute)) if (!(nodeByPath instanceof ChoiceNode) && !(nodeByPath instanceof ChoiceCaseNode)) { result.append(pathElement.localName) if (i != path.size - 1) { result.append("/") } } i = i + 1 } } return result.toString } private def void collectChildNodes(Collection source, Map destination) { for (node : source) { destination.put(node.path, node) if (node instanceof DataNodeContainer) { collectChildNodes((node as DataNodeContainer).childNodes, destination) } if (node instanceof ChoiceNode) { val List choiceCases = new ArrayList() for (caseNode : (node as ChoiceNode).cases) { choiceCases.add(caseNode) } collectChildNodes(choiceCases, destination) } } } private def CharSequence pathToTree(List path) ''' «IF path !== null && !path.empty»
      «FOR pathElement : path»
    • «pathElement.namespace» «pathElement.localName»
    • «ENDFOR»
    «ENDIF» ''' def dispatch addedByInfo(SchemaNode node) ''' ''' def dispatch addedByInfo(DataSchemaNode node) ''' «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF» ''' def dispatch isAddedBy(SchemaNode node) { return false; } def dispatch isAddedBy(DataSchemaNode node) { if (node.augmenting || node.addedByUses) { return true } else { return false; } } def dispatch nodeName(SchemaNode node) ''' «IF node.isAddedBy» «italic(node.QName.localName)»«node.addedByInfo» «ELSE» «strong(node.QName.localName)»«node.addedByInfo» «ENDIF» ''' def dispatch nodeName(ListSchemaNode node) ''' «IF node.isAddedBy» «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo» «ELSE» «strong(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF» «ENDIF» ''' }