/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.mdsal.binding.yang.unified.doc.generator import com.google.common.collect.Iterables import com.google.common.collect.Lists import java.io.BufferedWriter import java.io.File import java.io.IOException import java.io.OutputStreamWriter import java.nio.charset.StandardCharsets import java.util.ArrayList import java.util.Collection import java.util.HashMap import java.util.HashSet import java.util.LinkedHashMap import java.util.List import java.util.Map import java.util.Optional import java.util.Set import org.gaul.modernizer_maven_annotations.SuppressModernizer import org.opendaylight.yangtools.yang.common.QName import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode import org.opendaylight.yangtools.yang.model.api.AugmentationTarget import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode import org.opendaylight.yangtools.yang.model.api.DataNodeContainer import org.opendaylight.yangtools.yang.model.api.DataSchemaNode import org.opendaylight.yangtools.yang.model.api.ElementCountConstraintAware import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition import org.opendaylight.yangtools.yang.model.api.GroupingDefinition import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode import org.opendaylight.yangtools.yang.model.api.ListSchemaNode import org.opendaylight.yangtools.yang.model.api.Module import org.opendaylight.yangtools.yang.model.api.NotificationDefinition import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.yangtools.yang.model.api.SchemaNode import org.opendaylight.yangtools.yang.model.api.SchemaPath import org.opendaylight.yangtools.yang.model.api.TypeDefinition import org.opendaylight.yangtools.yang.model.api.UsesNode 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.Int8TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Int16TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Int32TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Int64TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition import org.slf4j.Logger import org.slf4j.LoggerFactory import org.sonatype.plexus.build.incremental.BuildContext @SuppressModernizer class GeneratorImpl { static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl) val Map imports = new HashMap(); var Module currentModule; var SchemaContext ctx; var File path StringBuilder augmentChildNodesAsString DataSchemaNode lastNodeInTargetPath = null def generate(BuildContext buildContext, SchemaContext context, File targetPath, Set modulesToGen) throws IOException { path = targetPath; path.mkdirs(); val it = new HashSet; for (module : modulesToGen) { add(generateDocumentation(buildContext, module, context)); } return it; } def generateDocumentation(BuildContext buildContext, Module module, SchemaContext ctx) { val destination = new File(path, '''«module.name».html''') this.ctx = ctx; module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)] try { val fw = new OutputStreamWriter(buildContext.newFileOutputStream(destination), StandardCharsets.UTF_8) val bw = new BufferedWriter(fw) currentModule = module; bw.append(generate(module, ctx)); bw.close(); fw.close(); } catch (IOException e) { LOG.error(e.getMessage()); } return destination; } def generate(Module module, SchemaContext ctx) ''' «module.name» «body(module, ctx)» ''' def body(Module module, SchemaContext ctx) ''' «header(module)» «typeDefinitionsSummary(module)» «identitiesSummary(module)» «groupingsSummary(module)» «augmentationsSummary(module, ctx)» «objectsSummary(module)» «notificationsSummary(module)» «rpcsSummary(module)» «extensionsSummary(module)» «featuresSummary(module)» «typeDefinitions(module)» «identities(module)» «groupings(module)» «dataStore(module)» «childNodes(module)» «notifications(module)» «augmentations(module, ctx)» «rpcs(module)» «extensions(module)» «features(module)» ''' private def typeDefinitionsSummary(Module module) { val Set> typedefs = module.typeDefinitions if (typedefs.empty) { return ''; } return '''

Type Definitions Summary

«FOR typedef : typedefs» «ENDFOR»
Name Description
«anchorLink(typedef.QName.localName, strong(typedef.QName.localName))» «typedef.description»
''' } def typeDefinitions(Module module) { val Set> typedefs = module.typeDefinitions if (typedefs.empty) { return ''; } return '''

Type Definitions

    «FOR typedef : typedefs»
  • «typedef.QName.localName»

      «typedef.descAndRefLi» «typedef.restrictions»
  • «ENDFOR»
''' } private def identities(Module module) { if (module.identities.empty) { return ''; } return '''

Identities

    «FOR identity : module.identities»
  • «identity.QName.localName»

      «identity.descAndRefLi» «IF !identity.baseIdentities.isEmpty» «listItem("base", identity.baseIdentities.get(0).QName.localName)» «ENDIF»
  • «ENDFOR»
''' } private def identitiesSummary(Module module) { if (module.identities.empty) { return ''; } return '''

Identities Summary

«FOR identity : module.identities» «ENDFOR»
Name Description
«anchorLink(identity.QName.localName, strong(identity.QName.localName))» «identity.description»
''' } private def groupings(Module module) { if (module.groupings.empty) { return ''; } return '''

Groupings

    «FOR grouping : module.groupings»
  • «grouping.QName.localName»

      «grouping.descAndRefLi» «FOR childNode : grouping.childNodes» «childNode.printSchemaNodeInfo» «ENDFOR»
  • «ENDFOR»
''' } private def groupingsSummary(Module module) { if (module.groupings.empty) { return ''; } return '''

Groupings Summary

«FOR grouping : module.groupings» «ENDFOR»
Name Description
«anchorLink(grouping.QName.localName, strong(grouping.QName.localName))» «grouping.description»
''' } def dataStore(Module module) { if (module.childNodes.empty) { return ''; } return '''

Datastore Structure

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

Augmentations

    «FOR augment : module.augmentations»
  • Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]

    «augment.description» Status: «strong(String.valueOf(augment.status))» «IF augment.reference !== null» Reference «augment.reference» «ENDIF» «IF augment.whenCondition !== null» When «augment.whenCondition.toString» «ENDIF» «FOR childNode : augment.childNodes» «childNode.printSchemaNodeInfo» «ENDFOR»

    Example

    «createAugmentChildNodesAsString(new ArrayList(augment.childNodes))» «printNodeChildren(parseTargetPath(augment.targetPath))»
  • «ENDFOR»
''' } private def createAugmentChildNodesAsString(List childNodes) { augmentChildNodesAsString = new StringBuilder(); augmentChildNodesAsString.append(printNodeChildren(childNodes)) return '' } private def parseTargetPath(SchemaPath path) { val List nodes = new ArrayList(); for (QName pathElement : path.pathFromRoot) { val module = ctx.findModule(pathElement.module) if (module.isPresent) { var foundNode = module.get.getDataChildByName(pathElement) if (foundNode === null) { val child = nodes.last if (child instanceof DataNodeContainer) { val dataContNode = child as DataNodeContainer foundNode = findNodeInChildNodes(pathElement, dataContNode.childNodes) } } if (foundNode !== null) { nodes.add(foundNode); } } } if (!nodes.empty) { lastNodeInTargetPath = nodes.get(nodes.size() - 1) } val List targetPathNodes = new ArrayList(); targetPathNodes.add(lastNodeInTargetPath) return targetPathNodes } private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable childNodes) { for(child : childNodes) { if (child.QName.equals(findingNode)) return child; } // find recursively for(child : childNodes) { if (child instanceof ContainerSchemaNode) { val foundChild = findNodeInChildNodes(findingNode, child.childNodes) if (foundChild !== null) return foundChild; } else if (child instanceof ListSchemaNode) { val foundChild = findNodeInChildNodes(findingNode, child.childNodes) if (foundChild !== null) return foundChild; } } } private def printNodeChildren(List childNodes) { if (childNodes.empty) { return '' } return '''
        «printAugmentedNode(childNodes.get(0))»
        
''' } private def CharSequence printAugmentedNode(DataSchemaNode child) { if(child instanceof CaseSchemaNode) return '' return ''' «IF child instanceof ContainerSchemaNode» «printContainerNode(child)» «ENDIF» «IF child instanceof AnyxmlSchemaNode» «printAnyXmlNode(child)» «ENDIF» «IF child instanceof LeafSchemaNode» «printLeafNode(child)» «ENDIF» «IF child instanceof LeafListSchemaNode» «printLeafListNode(child)» «ENDIF» «IF child instanceof ListSchemaNode» «printListNode(child)» «ENDIF» «IF child instanceof ChoiceSchemaNode» «printChoiceNode(child)» «ENDIF» ''' } private def printChoiceNode(ChoiceSchemaNode child) { val List cases = new ArrayList(child.cases.values); if(!cases.empty) { val CaseSchemaNode aCase = cases.get(0) for(caseChildNode : aCase.childNodes) printAugmentedNode(caseChildNode) } } private def printListNode(ListSchemaNode listNode) { return ''' <«listNode.QName.localName»«IF !listNode.QName.namespace.equals(currentModule.namespace)» xmlns="«listNode.QName.namespace»"«ENDIF»> «FOR child : listNode.childNodes» «printAugmentedNode(child)» «ENDFOR» </«listNode.QName.localName»> ''' } private def printContainerNode(ContainerSchemaNode containerNode) { return ''' <«containerNode.QName.localName»«IF !containerNode.QName.namespace.equals(currentModule.namespace)» xmlns="«containerNode.QName.namespace»"«ENDIF»> «FOR child : containerNode.childNodes» «printAugmentedNode(child)» «ENDFOR» </«containerNode.QName.localName»> ''' } private def printLeafListNode(LeafListSchemaNode leafListNode) { return ''' <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»> <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»> <«leafListNode.QName.localName»>. . .</«leafListNode.QName.localName»> ''' } private def printAnyXmlNode(AnyxmlSchemaNode anyXmlNode) { return ''' <«anyXmlNode.QName.localName»>. . .</«anyXmlNode.QName.localName»> ''' } private def printLeafNode(LeafSchemaNode leafNode) { return ''' <«leafNode.QName.localName»>. . .</«leafNode.QName.localName»> ''' } private def augmentationsSummary(Module module, SchemaContext context) { if (module.augmentations.empty) { return ''; } return '''

Augmentations Summary

«FOR augment : module.augmentations» «ENDFOR»
Target Description
«anchorLink(schemaPathToString(module, augment.targetPath, context, augment), strong(schemaPathToString(module, augment.targetPath, context, augment)))» «augment.description»
''' } def notifications(Module module) { val Set notificationdefs = module.notifications if (notificationdefs.empty) { return ''; } return '''

Notifications

«FOR notificationdef : notificationdefs»

«notificationdef.nodeName»

«notificationdef.descAndRef» «FOR childNode : notificationdef.childNodes» «childNode.printSchemaNodeInfo» «ENDFOR» «ENDFOR» ''' } private def notificationsSummary(Module module) { if (module.notifications.empty) { return ''; } return '''

Notifications Summary

«FOR notification : module.notifications» «ENDFOR»
Name Description
«anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))» «notification.description»
''' } def rpcs(Module module) { if (module.rpcs.empty) { return ''; } return '''

RPC Definitions

«FOR rpc : module.rpcs»

«rpc.nodeName»

    «rpc.descAndRefLi» «rpc.input.printSchemaNodeInfo» «rpc.output.printSchemaNodeInfo»
«ENDFOR» ''' } private def rpcsSummary(Module module) { if (module.rpcs.empty) { return ''; } return '''

RPCs Summary

«FOR rpc : module.rpcs» «ENDFOR»
Name Description
«anchorLink(rpc.QName.localName, strong(rpc.QName.localName))» «rpc.description»
''' } def extensions(Module module) { if (module.extensionSchemaNodes.empty) { return ''; } return '''

Extensions

«FOR ext : module.extensionSchemaNodes»
  • «ext.nodeName»

  • «extensionInfo(ext)» «ENDFOR» ''' } private def extensionsSummary(Module module) { if (module.extensionSchemaNodes.empty) { return ''; } return '''

    Extensions Summary

    «FOR ext : module.extensionSchemaNodes» «ENDFOR»
    Name Description
    «anchorLink(ext.QName.localName, strong(ext.QName.localName))» «ext.description»
    ''' } def features(Module module) { if (module.features.empty) { return ''; } return '''

    Features

      «FOR feature : module.features»
    • «feature.QName.localName»

        «feature.descAndRefLi»
    • «ENDFOR»
    ''' } private def featuresSummary(Module module) { if (module.features.empty) { return ''; } return '''

    Features Summary

    «FOR feature : module.features» «ENDFOR»
    Name Description
    «anchorLink(feature.QName.localName, strong(feature.QName.localName))» «feature.description»
    ''' } private def objectsSummary(Module module) { if (module.childNodes.empty) { return ''; } return '''

    Child Nodes Summary

    «FOR childNode : module.childNodes» «ENDFOR»
    Name Description
    «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))» «childNode.description»
    ''' } def header(Module module) '''

    «module.name»

    Base Information

    «IF module.revision.isPresent» «ENDIF» «FOR imp : module.imports BEFORE ''''''» «imp.prefix»:«imp.moduleName»«IF imp.revision.isPresent» «imp.revision.get.toString»«ENDIF»; «ENDFOR»
    «strong("prefix")» «module.prefix»
    «strong("namespace")» «module.namespace»
    «strong("revision")» «module.revision.get.toString»
    «strong("description")» «module.description»
    «strong("yang-version")» «module.yangVersion»
    «strong("imports")»''' AFTER '''
    ''' def CharSequence schemaPathToId(SchemaPath path) { if(path !== null) { return '''«FOR qName : path.pathFromRoot SEPARATOR "/"»«qName.localName»«ENDFOR»''' } } def code(String string) '''«string»''' def process(Module module) { throw new UnsupportedOperationException("TODO: auto-generated method stub") } def CharSequence tree(Module module) ''' «strong(module.name)» «module.childNodes.treeSet(YangInstanceIdentifier.builder.build())» ''' private def dispatch CharSequence tree(ChoiceSchemaNode node,YangInstanceIdentifier path) ''' «node.nodeName» (choice) «casesTree(node.cases.values, path)» ''' def casesTree(Collection nodes, YangInstanceIdentifier path) '''
      «FOR node : nodes»
    • «node.nodeName» «node.childNodes.treeSet(path)»
    • «ENDFOR»
    ''' private def dispatch CharSequence tree(DataSchemaNode node,YangInstanceIdentifier path) ''' «node.nodeName» ''' private def dispatch CharSequence tree(ListSchemaNode node,YangInstanceIdentifier path) ''' «val newPath = path.append(node)» «localLink(newPath,node.nodeName)» «node.childNodes.treeSet(newPath)» ''' private def dispatch CharSequence tree(ContainerSchemaNode node,YangInstanceIdentifier path) ''' «val newPath = path.append(node)» «localLink(newPath,node.nodeName)» «node.childNodes.treeSet(newPath)» ''' def CharSequence childNodes(Module module) ''' «val childNodes = module.childNodes» «IF !childNodes.nullOrEmpty»

    Child nodes

    «childNodes.printChildren(3,YangInstanceIdentifier.builder().build())» «ENDIF» ''' def CharSequence printSchemaNodeInfo(DataSchemaNode node) { return '''
      «node.printBaseInfo» «IF node instanceof DataNodeContainer» «val dataNode = node as DataNodeContainer»
        «FOR usesNode : dataNode.uses» «usesNode.printUses» «ENDFOR»
        «val Set> typeDefinitions = dataNode.typeDefinitions» «FOR typeDef : typeDefinitions» «typeDef.restrictions» «ENDFOR»
        «FOR grouping : dataNode.groupings» «grouping.printGrouping» «ENDFOR»
        «FOR child : dataNode.childNodes» «child.printSchemaNodeInfo» «ENDFOR»
      «ENDIF»
    ''' } def String typeAnchorLink(SchemaPath path, CharSequence text) { if(path !== null) { val lastElement = Iterables.getLast(path.pathFromRoot) val ns = lastElement.namespace if (ns == this.currentModule.namespace) { return '''«text»''' } else { return '''(«ns»)«text»''' //to enable external (import) links //return '''«prefix»:«text»''' } } } def CharSequence printBaseInfo(SchemaNode node) { if(node instanceof LeafSchemaNode) { return ''' «printInfo(node, "leaf")» «listItem("type", typeAnchorLink(node.type?.path, node.type.QName.localName))» «listItem("units", node.type.units.orElse(null))» «listItem("default", node.type.defaultValue.map([ Object o | o.toString]).orElse(null))» ''' } else if(node instanceof LeafListSchemaNode) { return ''' «printInfo(node, "leaf-list")» «listItem("type", node.type?.QName.localName)» ''' } else if(node instanceof ListSchemaNode) { return ''' «printInfo(node, "list")» «FOR keyDef : node.keyDefinition» «listItem("key definition", keyDef.localName)» «ENDFOR» ''' } else if(node instanceof ChoiceSchemaNode) { return ''' «printInfo(node, "choice")» «listItem("default case", node.defaultCase.map([ CaseSchemaNode n | n.getQName.localName]).orElse(null))» «FOR caseNode : node.cases.values» «caseNode.printSchemaNodeInfo» «ENDFOR» ''' } else if(node instanceof CaseSchemaNode) { return ''' «printInfo(node, "case")» ''' } else if(node instanceof ContainerSchemaNode) { return ''' «printInfo(node, "container")» ''' } else if(node instanceof AnyxmlSchemaNode) { return ''' «printInfo(node, "anyxml")» ''' } } def CharSequence printInfo(SchemaNode node, String nodeType) { return ''' «IF node instanceof AugmentationTarget» «IF node !== null»
  • «nodeType»: «node.QName.localName»
  • «ENDIF» «ELSE» «strong(listItem(nodeType, node.QName.localName))» «ENDIF»
      «listItem("description", node.description.orElse(null))» «listItem("reference", node.reference.orElse(null))» «IF node instanceof DataSchemaNode» «IF node.whenCondition.present» «listItem("when condition", node.whenCondition.get.toString)» «ENDIF» «ENDIF» «IF node instanceof ElementCountConstraintAware» «IF node.elementCountConstraint.present» «val constraint = node.elementCountConstraint.get» «listItem("min elements", constraint.minElements?.toString)» «listItem("max elements", constraint.maxElements?.toString)» «ENDIF» «ENDIF» ''' } def CharSequence printUses(UsesNode usesNode) { return ''' «strong(listItem("uses", typeAnchorLink(usesNode.groupingPath, usesNode.groupingPath.pathTowardsRoot.iterator.next.localName)))»
      • refines:
          «FOR sp : usesNode.refines.keySet» «listItem("node name", usesNode.refines.get(sp).QName.localName)» «ENDFOR»
      • «FOR augment : usesNode.augmentations» «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))» «ENDFOR»
      ''' } def CharSequence printGrouping(GroupingDefinition grouping) { return ''' «strong(listItem("grouping", grouping.QName.localName))» ''' } def CharSequence printChildren(Iterable nodes, int level, YangInstanceIdentifier path) { val anyxmlNodes = nodes.filter(AnyxmlSchemaNode) val leafNodes = nodes.filter(LeafSchemaNode) val leafListNodes = nodes.filter(LeafListSchemaNode) val choices = nodes.filter(ChoiceSchemaNode) val cases = nodes.filter(CaseSchemaNode) val containers = nodes.filter(ContainerSchemaNode) val lists = nodes.filter(ListSchemaNode) return ''' «IF ((anyxmlNodes.size + leafNodes.size + leafListNodes.size + containers.size + lists.size) > 0)»

      Direct children

        «FOR childNode : anyxmlNodes» «childNode.printShortInfo(level,path)» «ENDFOR» «FOR childNode : leafNodes» «childNode.printShortInfo(level,path)» «ENDFOR» «FOR childNode : leafListNodes» «childNode.printShortInfo(level,path)» «ENDFOR» «FOR childNode : containers» «childNode.printShortInfo(level,path)» «ENDFOR» «FOR childNode : lists» «childNode.printShortInfo(level,path)» «ENDFOR»
      «ENDIF» «IF path.pathArguments.iterator.hasNext»

      XML example

      «nodes.xmlExample(path.pathArguments.last.nodeType,path)» «ENDIF» «FOR childNode : containers» «childNode.printInfo(level,path)» «ENDFOR» «FOR childNode : lists» «childNode.printInfo(level,path)» «ENDFOR» «FOR childNode : choices» «childNode.printInfo(level,path)» «ENDFOR» «FOR childNode : cases» «childNode.printInfo(level,path)» «ENDFOR» ''' } def CharSequence xmlExample(Iterable nodes, QName name,YangInstanceIdentifier path) '''
              «xmlExampleTag(name,nodes.xmplExampleTags(path))»
          
      ''' def CharSequence xmplExampleTags(Iterable nodes, YangInstanceIdentifier identifier) ''' «FOR node : nodes» «node.asXmlExampleTag(identifier)» «ENDFOR» ''' private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, YangInstanceIdentifier identifier) ''' «node.QName.xmlExampleTag("...")» ''' private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, YangInstanceIdentifier identifier) ''' <!-- This node could appear multiple times --> «node.QName.xmlExampleTag("...")» ''' private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, YangInstanceIdentifier identifier) ''' <!-- See «localLink(identifier.append(node),"definition")» for child nodes. --> «node.QName.xmlExampleTag("...")» ''' private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, YangInstanceIdentifier identifier) ''' <!-- See «localLink(identifier.append(node),"definition")» for child nodes. --> <!-- This node could appear multiple times --> «node.QName.xmlExampleTag("...")» ''' private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) ''' ''' def xmlExampleTag(QName name, CharSequence data) { return '''<«name.localName» xmlns="«name.namespace»">«data»</«name.localName»>''' } def header(int level,QName name) '''«name.localName»''' def header(int level,YangInstanceIdentifier name) ''' «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR» ''' private def dispatch CharSequence printInfo(DataSchemaNode node, int level, YangInstanceIdentifier path) ''' «header(level+1,node.QName)» ''' private def dispatch CharSequence printInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) ''' «val newPath = path.append(node)» «header(level,newPath)»
      XML Path
      «newPath.asXmlPath»
      Restconf path
      «code(newPath.asRestconfPath)»
      «node.childNodes.printChildren(level,newPath)» ''' private def dispatch CharSequence printInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) ''' «val newPath = path.append(node)» «header(level,newPath)»
      XML Path
      «newPath.asXmlPath»
      Restconf path
      «code(newPath.asRestconfPath)»
      «node.childNodes.printChildren(level,newPath)» ''' private def dispatch CharSequence printInfo(ChoiceSchemaNode node, int level, YangInstanceIdentifier path) ''' «val Set choiceCases = new HashSet(node.cases.values)» «choiceCases.printChildren(level, path)» ''' private def dispatch CharSequence printInfo(CaseSchemaNode node, int level, YangInstanceIdentifier path) ''' «node.childNodes.printChildren(level, path)» ''' def CharSequence printShortInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) { val newPath = path.append(node); return '''
    • «strong(localLink(newPath,node.QName.localName))» (container)
      • configuration data: «strong(String.valueOf(node.configuration))»
    • ''' } def CharSequence printShortInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) { val newPath = path.append(node); return '''
    • «strong(localLink(newPath,node.QName.localName))» (list)
      • configuration data: «strong(String.valueOf(node.configuration))»
    • ''' } def CharSequence printShortInfo(AnyxmlSchemaNode node, int level, YangInstanceIdentifier path) { return '''
    • «strong((node.QName.localName))» (anyxml)
      • configuration data: «strong(String.valueOf(node.configuration))»
      • mandatory: «strong(String.valueOf(node.mandatory))»
    • ''' } def CharSequence printShortInfo(LeafSchemaNode node, int level, YangInstanceIdentifier path) { return '''
    • «strong((node.QName.localName))» (leaf)
      • configuration data: «strong(String.valueOf(node.configuration))»
      • mandatory: «strong(String.valueOf(node.mandatory))»
    • ''' } def CharSequence printShortInfo(LeafListSchemaNode node, int level, YangInstanceIdentifier path) { return '''
    • «strong((node.QName.localName))» (leaf-list)
      • configuration data: «strong(String.valueOf(node.configuration))»
    • ''' } def CharSequence anchorLink(CharSequence anchor, CharSequence text) { return ''' «text» ''' } def CharSequence localLink(YangInstanceIdentifier identifier, CharSequence text) ''' «text» ''' private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ContainerSchemaNode node) { return identifier.node(node.QName); } private def dispatch YangInstanceIdentifier append(YangInstanceIdentifier identifier, ListSchemaNode node) { val keyValues = new LinkedHashMap(); if(node.keyDefinition !== null) { for(definition : node.keyDefinition) { keyValues.put(definition,new Object); } } return identifier.node(NodeIdentifierWithPredicates.of(node.QName, keyValues)); } def asXmlPath(YangInstanceIdentifier identifier) { return ""; } def asRestconfPath(YangInstanceIdentifier identifier) { val it = new StringBuilder(); append(currentModule.name) append(':') var previous = false; for(arg : identifier.pathArguments) { if(previous) append('/') append(arg.nodeType.localName); previous = true; if(arg instanceof NodeIdentifierWithPredicates) { for(qname : arg.keySet) { append("/{"); append(qname.localName) append('}') } } } return it.toString; } private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) { val List path = Lists.newArrayList(schemaPath.pathFromRoot); val StringBuilder pathString = new StringBuilder() if (schemaPath.absolute) { pathString.append('/') } val QName qname = path.get(0) var Object parent = ctx.findModule(qname.module).orElse(null) for (name : path) { if (parent instanceof DataNodeContainer) { var SchemaNode node = parent.getDataChildByName(name) if (node === null && (parent instanceof Module)) { val notifications = (parent as Module).notifications; for (notification : notifications) { if (notification.QName.equals(name)) { node = notification } } } if (node === null && (parent instanceof Module)) { val rpcs = (parent as Module).rpcs; for (rpc : rpcs) { if (rpc.QName.equals(name)) { node = rpc } } } val pathElementModule = ctx.findModule(name.module).get val String moduleName = pathElementModule.name pathString.append(moduleName) pathString.append(':') pathString.append(name.localName) pathString.append('/') if(node instanceof ChoiceSchemaNode && dataNode !== null) { val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof CaseSchemaNode]; if(caseNode !== null) { pathString.append("(case)"); pathString.append(caseNode.QName.localName); } } parent = node } } return pathString.toString; } 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» «code(path)» «IF node !== null»
        «node.descAndRefLi»
      «ENDIF» «ENDIF» ''' private def CharSequence treeSet(Collection childNodes, YangInstanceIdentifier path) ''' «IF childNodes !== null && !childNodes.empty»
        «FOR child : childNodes»
      • «child.tree(path)»
      • «ENDFOR»
      «ENDIF» ''' def listKeys(ListSchemaNode node) ''' [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»] ''' private def CharSequence extensionInfo(ExtensionDefinition ext) '''
        «ext.descAndRefLi» «listItem("Argument", ext.argument)»
      ''' private def dispatch CharSequence tree(Void obj, YangInstanceIdentifier path) ''' ''' /* #################### RESTRICTIONS #################### */ private def restrictions(TypeDefinition type) ''' «type.baseType.toBaseStmt» «type.toLength» «type.toRange» ''' private def dispatch toLength(TypeDefinition type) { } private def dispatch toLength(BinaryTypeDefinition type) ''' «type.lengthConstraint.toLengthStmt» ''' private def dispatch toLength(StringTypeDefinition type) ''' «type.lengthConstraint.toLengthStmt» ''' private def dispatch toRange(TypeDefinition type) { } private def dispatch toRange(DecimalTypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Int8TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Int16TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Int32TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Int64TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Uint8TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Uint16TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Uint32TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' private def dispatch toRange(Uint64TypeDefinition type) ''' «type.rangeConstraint.toRangeStmt» ''' def toLengthStmt(Optional lengths) ''' «IF lengths.isPresent» «listItem("Length restrictions:")»
        «FOR length : lengths.get.allowedRanges.asRanges»
      • «IF length.lowerEndpoint == length.upperEndpoint» «length.lowerEndpoint» «ELSE» <«length.lowerEndpoint», «length.upperEndpoint»> «ENDIF»
      • «ENDFOR»
      «ENDIF» ''' def toRangeStmt(Optional> constraint) ''' «IF constraint.present» «listItem("Range restrictions:")»
        «FOR range : constraint.get.allowedRanges.asRanges»
      • «IF range.lowerEndpoint == range.upperEndpoint» «range.lowerEndpoint» «ELSE» <«range.lowerEndpoint», «range.upperEndpoint»> «ENDIF»
      • «ENDFOR»
      «ENDIF» ''' def toBaseStmt(TypeDefinition baseType) ''' «IF baseType !== null» «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))» «ENDIF» ''' /* #################### UTILITY #################### */ private def String strong(CharSequence str) '''«str»''' private def italic(CharSequence str) '''«str»''' def CharSequence descAndRefLi(SchemaNode node) ''' «listItem("Description", node.description.orElse(null))» «listItem("Reference", node.reference.orElse(null))» ''' def CharSequence descAndRef(SchemaNode node) ''' «node.description» «IF node.reference !== null» Reference «node.reference» «ENDIF» ''' 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 ChoiceSchemaNode || node instanceof CaseSchemaNode) { return null } val path = node.path.pathFromRoot 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(SchemaPath.create(actual, absolute)) if (!(nodeByPath instanceof ChoiceSchemaNode) && !(nodeByPath instanceof CaseSchemaNode)) { result.append(pathElement.localName) if (i != path.size - 1) { result.append('/') } } i = i + 1 } } return result.toString } private def dispatch addedByInfo(SchemaNode node) ''' ''' private def dispatch addedByInfo(DataSchemaNode node) ''' «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF» ''' private def dispatch isAddedBy(SchemaNode node) { return false; } private def dispatch isAddedBy(DataSchemaNode node) { if (node.augmenting || node.addedByUses) { return true } else { return false; } } private def dispatch nodeName(SchemaNode node) ''' «IF node.isAddedBy» «italic(node.QName.localName)»«node.addedByInfo» «ELSE» «node.QName.localName»«node.addedByInfo» «ENDIF» ''' private def dispatch nodeName(ContainerSchemaNode node) ''' «IF node.isAddedBy» «strong(italic(node.QName.localName))»«node.addedByInfo» «ELSE» «strong(node.QName.localName)»«node.addedByInfo» «ENDIF» ''' private def dispatch nodeName(ListSchemaNode node) ''' «IF node.isAddedBy» «strong(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» ''' }