X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=code-generator%2Fmaven-sal-api-gen-plugin%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Funified%2Fdoc%2Fgenerator%2FGeneratorImpl.xtend;h=185299d190f35dca2e35424b3e40e577e195e526;hb=65cbb409d1fd696313d8f237c86a10cd7e23c1b4;hp=965fd75235dac8705088b8905167fb41b72e756d;hpb=4591041ed0521ad241b7ef4fea157eb1eedd192e;p=mdsal.git diff --git a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend index 965fd75235..185299d190 100644 --- a/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend +++ b/code-generator/maven-sal-api-gen-plugin/src/main/java/org/opendaylight/yangtools/yang/unified/doc/generator/GeneratorImpl.xtend @@ -1,62 +1,94 @@ +/* + * 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.yangtools.yang.unified.doc.generator -import org.opendaylight.yangtools.yang.model.api.SchemaContext +import java.io.BufferedWriter import java.io.File -import java.util.Set -import org.opendaylight.yangtools.yang.model.api.Module import java.io.IOException +import java.io.OutputStreamWriter +import java.text.SimpleDateFormat +import java.util.ArrayList +import java.util.Collection +import java.util.HashMap import java.util.HashSet -import java.io.FileWriter -import java.io.BufferedWriter +import java.util.LinkedHashMap +import java.util.List +import java.util.Map +import java.util.Set +import org.opendaylight.yangtools.yang.common.QName +import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode +import org.opendaylight.yangtools.yang.model.api.ChoiceNode +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.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.TypeDefinition +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.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.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.RangeConstraint import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition +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.UnsignedIntegerTypeDefinition -import org.opendaylight.yangtools.yang.model.api.NotificationDefinition -import org.opendaylight.yangtools.yang.model.api.DataNodeContainer -import org.slf4j.LoggerFactory +import org.opendaylight.yangtools.yang.model.util.ExtendedType 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 org.slf4j.LoggerFactory +import org.sonatype.plexus.build.incremental.BuildContext +import org.sonatype.plexus.build.incremental.DefaultBuildContext +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier +import com.google.common.collect.Iterables class GeneratorImpl { File path static val REVISION_FORMAT = new SimpleDateFormat("yyyy-MM-dd") static val Logger LOG = LoggerFactory.getLogger(GeneratorImpl) - + static val BuildContext CTX = new DefaultBuildContext(); + var Module currentModule; + val Map imports = new HashMap(); + var SchemaContext ctx; + + StringBuilder augmentChildNodesAsString + + DataSchemaNode lastNodeInTargetPath = null def generate(SchemaContext context, File targetPath, Set modulesToGen) throws IOException { path = targetPath; path.mkdirs(); val it = new HashSet; for (module : modulesToGen) { - add(module.generateDocumentation()); + add(generateDocumentation(module, context)); } return it; } - def generateDocumentation(Module module) { + def generateDocumentation(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 FileWriter(destination) - destination.createNewFile(); + val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination)) val bw = new BufferedWriter(fw) - - bw.append(module.generate); + currentModule = module; + bw.append(generate(module, ctx)); bw.close(); fw.close(); } catch (IOException e) { @@ -65,38 +97,82 @@ class GeneratorImpl { return destination; } - def generate(Module module) ''' + def generate(Module module, SchemaContext ctx) ''' «module.name» - «module.body» + «body(module, ctx)» ''' - def body(Module module) ''' + 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)» + «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» +
NameDescription
+ «anchorLink(typedef.QName.localName, strong(typedef.QName.localName))» + + «typedef.description» +
+
+ ''' + } + def typeDefinitions(Module module) { val Set> typedefs = module.typeDefinitions if (typedefs.empty) { @@ -104,31 +180,111 @@ class GeneratorImpl { } return '''

Type Definitions

- «list(typedefs)» - +
    «FOR typedef : typedefs» - «typeDefinition(typedef)» +
  • +

    «typedef.QName.localName»

    +
      + «typedef.descAndRefLi» + «typedef.restrictions» +
    +
  • «ENDFOR» +
''' } - private def CharSequence typeDefinition(TypeDefinition type) ''' - «header(type)» - «body(type)» - «restrictions(type)» - ''' + private def identities(Module module) { + if (module.identities.empty) { + return ''; + } + return ''' +

Identities

+
    + «FOR identity : module.identities» +
  • +

    «identity.QName.localName»

    +
      + «identity.descAndRefLi» + «IF identity.baseIdentity !== null» + «listItem("base", identity.baseIdentity.QName.localName)» + «ENDIF» +
    +
  • + «ENDFOR» +
+ ''' + } + + private def identitiesSummary(Module module) { + if (module.identities.empty) { + return ''; + } + return ''' +

Identities Summary

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

Groupings

- «list(module.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» - «headerAndBody(grouping)» + + + + «ENDFOR» +
NameDescription
+ «anchorLink(grouping.QName.localName, strong(grouping.QName.localName))» + + «grouping.description» +
''' } @@ -142,40 +298,257 @@ class GeneratorImpl { ''' } - def augmentations(Module module) { + def augmentations(Module module, SchemaContext context) { if (module.augmentations.empty) { return ''; } return '''

Augmentations

- +
    «FOR augment : module.augmentations»
  • - augment - «augment.tree» +

    + 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.findModuleByNamespaceAndRevision(pathElement.namespace, pathElement.revision); + if (module !== null) { + var foundNode = module.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 contChild = child as ContainerSchemaNode + val foundChild = findNodeInChildNodes(findingNode, contChild.childNodes) + if (foundChild != null) + return foundChild; + } + else if(child instanceof ListSchemaNode) { + val listChild = child as ListSchemaNode + val foundChild = findNodeInChildNodes(findingNode, listChild.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 ChoiceCaseNode) + return '' + + return + ''' + «IF child instanceof ContainerSchemaNode» + «printContainerNode(child as ContainerSchemaNode)» + «ENDIF» + «IF child instanceof AnyXmlSchemaNode» + «printAnyXmlNode(child as AnyXmlSchemaNode)» + «ENDIF» + «IF child instanceof LeafSchemaNode» + «printLeafNode(child as LeafSchemaNode)» + «ENDIF» + «IF child instanceof LeafListSchemaNode» + «printLeafListNode(child as LeafListSchemaNode)» + «ENDIF» + «IF child instanceof ListSchemaNode» + «printListNode(child as ListSchemaNode)» + «ENDIF» + «IF child instanceof ChoiceNode» + «printChoiceNode(child as ChoiceNode)» + «ENDIF» + ''' + } + + private def printChoiceNode(ChoiceNode child) { + val List cases = new ArrayList(child.cases); + if(!cases.empty) { + val ChoiceCaseNode 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» +
TargetDescription
+ «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.tree» -
  • + +

    «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» +
NameDescription
+ «anchorLink(notification.path.schemaPathToId, strong(notification.QName.localName))» + + «notification.description» +
''' } @@ -183,231 +556,791 @@ class GeneratorImpl { if (module.rpcs.empty) { return ''; } + return '''

RPC Definitions

- -
    «FOR rpc : module.rpcs» -
  • - «rpc.nodeName» - «rpc.tree» -
  • +

    «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» +
NameDescription
+ «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» +
      NameDescription
      + «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»
      • - «ext.nodeName» - «ext.tree» +

        «feature.QName.localName»

        +
          + «feature.descAndRefLi» +
      • «ENDFOR»
      ''' } - def CharSequence headerAndBody(SchemaNode node) ''' - «header(node)» - «body(node)» + private def featuresSummary(Module module) { + if (module.features.empty) { + return ''; + } + return ''' +

      Features Summary

      + + + + + + «FOR feature : module.features» + + + + + «ENDFOR» +
      NameDescription
      + «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» +
      NameDescription
      + «anchorLink(childNode.QName.localName, strong(childNode.QName.localName))» + + «childNode.description» +
      + ''' + } + + def header(Module module) ''' +

      «module.name»

      - def header(SchemaNode type) ''' -

      «type.QName.localName»

      +

      Base Information

      + + + + + + + + + + + + + + + + + + + + + + + «FOR imp : module.imports BEFORE ''''''» + «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»; + «ENDFOR» + +
      «strong("prefix")»«module.prefix»
      «strong("namespace")»«module.namespace»
      «strong("revision")»«REVISION_FORMAT.format(module.revision)»
      «strong("description")»«module.description»
      «strong("yang-version")»«module.yangVersion»
      «strong("imports")»''' AFTER '''
      ''' - def body(SchemaNode definition) ''' + def CharSequence schemaPathToId(SchemaPath path) { + if(path !== null) { + return '''«FOR qName : path.path SEPARATOR "/"»«qName.localName»«ENDFOR»''' + } + } + + def code(String string) '''«string»''' - «paragraphs(definition.description)» + def process(Module module) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } - «definition.reference» + def CharSequence tree(Module module) ''' + «strong(module.name)» + «module.childNodes.treeSet(YangInstanceIdentifier.builder.toInstance())» ''' + private def dispatch CharSequence tree(ChoiceNode node,YangInstanceIdentifier path) ''' + «node.nodeName» (choice) + «casesTree(node.cases,path)» + ''' - def list(Set definitions) ''' + def casesTree(Set nodes,YangInstanceIdentifier path) '''
        - «FOR nodeDef : definitions» -
      • «nodeDef.QName.localName»
      • + «FOR node : nodes» +
      • + «node.nodeName» + «node.childNodes.treeSet(path)» +
      • «ENDFOR»
      ''' - def header(Module module) ''' -

      «module.name»

      - -

      Base Information

      -
      -
      Prefix
      -
      «module.prefix»
      -
      Namespace
      -
      «module.namespace»
      -
      Revision
      -
      «REVISION_FORMAT.format(module.revision)»
      - - «FOR imp : module.imports BEFORE "
      Imports
      " » -
      «pre(imp.prefix)» = «pre(imp.moduleName)»
      + 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().toInstance())» + «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) { + val LeafSchemaNode leafNode = (node as LeafSchemaNode) + return ''' + «printInfo(node, "leaf")» + «listItem("type", typeAnchorLink(leafNode.type?.path, leafNode.type.QName.localName))» + «listItem("units", leafNode.units)» + «listItem("default", leafNode.^default)» +
    + ''' + } else if(node instanceof LeafListSchemaNode) { + val LeafListSchemaNode leafListNode = (node as LeafListSchemaNode) + return ''' + «printInfo(node, "leaf-list")» + «listItem("type", leafListNode.type?.QName.localName)» + + ''' + } else if(node instanceof ListSchemaNode) { + val ListSchemaNode listNode = (node as ListSchemaNode) + return ''' + «printInfo(node, "list")» + «FOR keyDef : listNode.keyDefinition» + «listItem("key definition", keyDef.localName)» + «ENDFOR» + + ''' + } else if(node instanceof ChoiceNode) { + val ChoiceNode choiceNode = (node as ChoiceNode) + return ''' + «printInfo(node, "choice")» + «listItem("default case", choiceNode.defaultCase)» + «FOR caseNode : choiceNode.cases» + «caseNode.printSchemaNodeInfo» + «ENDFOR» + + ''' + } else if(node instanceof ChoiceCaseNode) { + 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)» + «listItem("reference", node.reference)» + «IF node instanceof DataSchemaNode» + «listItem("when condition", (node as DataSchemaNode).constraints.whenCondition?.toString)» + «listItem("min elements", (node as DataSchemaNode).constraints.minElements?.toString)» + «listItem("max elements", (node as DataSchemaNode).constraints.maxElements?.toString)» + «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(ChoiceNode) + val cases = nodes.filter(ChoiceCaseNode) + 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» - def process(Module module) { - throw new UnsupportedOperationException("TODO: auto-generated method stub") + ''' + + 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»''' - /* #################### TREE STRUCTURE #################### */ - def dispatch CharSequence tree(Module module) ''' - «strong("module " + module.name)» - «module.childNodes.childrenToTree» + def header(int level,YangInstanceIdentifier name) ''' + + «FOR cmp : name.pathArguments SEPARATOR "/"»«cmp.nodeType.localName»«ENDFOR» + ''' - def dispatch CharSequence tree(DataNodeContainer node) ''' - «IF node instanceof SchemaNode» - «(node as SchemaNode).nodeName» - «ENDIF» - «node.childNodes.childrenToTree» + + + private def dispatch CharSequence printInfo(DataSchemaNode node, int level, YangInstanceIdentifier path) ''' + «header(level+1,node.QName)» ''' - def dispatch CharSequence tree(DataSchemaNode node) ''' - «node.nodeName» + 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)» ''' - def dispatch CharSequence tree(ListSchemaNode node) ''' - «node.nodeName» - «node.childNodes.childrenToTree» + 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 CharSequence childrenToTree(Collection childNodes) ''' - «IF childNodes !== null && !childNodes.empty» + private def dispatch CharSequence printInfo(ChoiceNode node, int level, YangInstanceIdentifier path) ''' + «val Set choiceCases = new HashSet(node.cases)» + «choiceCases.printChildren(level,path)» + ''' + + private def dispatch CharSequence printInfo(ChoiceCaseNode 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)
        - «FOR child : childNodes» -
      • - «child.tree» -
      • - «ENDFOR» +
      • configuration data: «strong(String.valueOf(node.configuration))»
      - «ENDIF» +
    • + ''' + } + + 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.constraints.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.constraints.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» ''' - def listKeys(ListSchemaNode node) ''' - [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»] + + 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(new NodeIdentifierWithPredicates(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) { + val nodeIdentifier = arg as NodeIdentifierWithPredicates; + for(qname : nodeIdentifier.getKeyValues.keySet) { + append("/{"); + append(qname.localName) + append("}") + } + } + } + + return it.toString; + } + + private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) { + val List path = schemaPath.path + val StringBuilder pathString = new StringBuilder() + if (schemaPath.absolute) { + pathString.append('/') + } + + val QName qname = path.get(0) + var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision) + + for (name : path) { + if (parent instanceof DataNodeContainer) { + var SchemaNode node = (parent as DataNodeContainer).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.findModuleByNamespaceAndRevision(name.namespace, name.revision) + val String moduleName = pathElementModule.name + pathString.append(moduleName) + pathString.append(':') + pathString.append(name.localName) + pathString.append('/') + if(node instanceof ChoiceNode && dataNode !== null) { + val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof ChoiceCaseNode]; + 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 dispatch CharSequence tree(AugmentationSchema augment) ''' -
        - «listItem("Description", augment.description)» - «listItem("Reference", augment.reference)» - «IF augment.whenCondition !== null» - «listItem("When", augment.whenCondition.toString)» + def CharSequence childInfo(DataSchemaNode node, Map childNodes) ''' + «val String path = nodeSchemaPathToPath(node, childNodes)» + «IF path != null» + «code(path)» + «IF node !== null» +
          + «node.descAndRefLi» +
        «ENDIF» -
      • - Path «augment.targetPath.path.pathToTree» -
      • -
      • - Child nodes - «augment.childNodes.childrenToTree» -
      • -
      + «ENDIF» ''' - private def CharSequence pathToTree(List path) ''' - «IF path !== null && !path.empty» + private def CharSequence treeSet(Collection childNodes, YangInstanceIdentifier path) ''' + «IF childNodes !== null && !childNodes.empty»
        - «FOR pathElement : path» + «FOR child : childNodes»
      • - «pathElement.namespace» «pathElement.localName» + «child.tree(path)»
      • «ENDFOR»
      «ENDIF» ''' - def dispatch CharSequence tree(NotificationDefinition notification) ''' -
        - «listItem("Description", notification.description)» - «listItem("Reference", notification.reference)» -
      • - Child nodes - «notification.childNodes.childrenToTree» -
      • -
      + def listKeys(ListSchemaNode node) ''' + [«FOR key : node.keyDefinition SEPARATOR " "»«key.localName»«ENDFOR»] ''' - def dispatch CharSequence tree(RpcDefinition rpc) ''' + private def CharSequence extensionInfo(ExtensionDefinition ext) '''
        - «listItem("Description", rpc.description)» - «listItem("Reference", rpc.reference)» -
      • - «rpc.input.tree» -
      • -
      • - «rpc.output.tree» -
      • + «ext.descAndRefLi» + «listItem("Argument", ext.argument)»
      ''' - def dispatch CharSequence tree(ExtensionDefinition ext) ''' -
        - «listItem("Description", ext.description)» - «listItem("Reference", ext.reference)» - «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» ''' - def dispatch toLength(TypeDefinition type) { + private def dispatch toLength(TypeDefinition type) { } - def dispatch toLength(BinaryTypeDefinition type) ''' + private def dispatch toLength(BinaryTypeDefinition type) ''' «type.lengthConstraints.toLengthStmt» ''' - def dispatch toLength(StringTypeDefinition type) ''' + private def dispatch toLength(StringTypeDefinition type) ''' «type.lengthConstraints.toLengthStmt» ''' - def dispatch toLength(ExtendedType type) ''' + private def dispatch toLength(ExtendedType type) ''' «type.lengthConstraints.toLengthStmt» ''' - def dispatch toRange(TypeDefinition type) { + private def dispatch toRange(TypeDefinition type) { } - def dispatch toRange(DecimalTypeDefinition type) ''' + private def dispatch toRange(DecimalTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' - def dispatch toRange(IntegerTypeDefinition type) ''' + private def dispatch toRange(IntegerTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' - def dispatch toRange(UnsignedIntegerTypeDefinition type) ''' + private def dispatch toRange(UnsignedIntegerTypeDefinition type) ''' «type.rangeConstraints.toRangeStmt» ''' - def dispatch toRange(ExtendedType type) ''' + private def dispatch toRange(ExtendedType type) ''' «type.rangeConstraints.toRangeStmt» ''' def toLengthStmt(Collection lengths) ''' «IF lengths != null && !lengths.empty» - «strong("Length restrictions")» + «listItem("Length restrictions:")»
        «FOR length : lengths»
      • @@ -424,7 +1357,7 @@ class GeneratorImpl { def toRangeStmt(Collection ranges) ''' «IF ranges != null && !ranges.empty» - «strong("Range restrictions")» + «listItem("Range restrictions:")»
          «FOR range : ranges»
        • @@ -439,48 +1372,103 @@ class GeneratorImpl { «ENDIF» ''' + def toBaseStmt(TypeDefinition baseType) ''' + «IF baseType != null» + «listItem("Base type", typeAnchorLink(baseType?.path, baseType.QName.localName))» + «ENDIF» + ''' + /* #################### UTILITY #################### */ - def strong(String str) ''' - «str» - ''' + private def String strong(CharSequence str) '''«str»''' + private def italic(CharSequence str) '''«str»''' - def italic(String str) ''' - «str» + def CharSequence descAndRefLi(SchemaNode node) ''' + «listItem("Description", node.description)» + «listItem("Reference", node.reference)» ''' - def pre(String string) '''
          «string»
          ''' + def CharSequence descAndRef(SchemaNode node) ''' + «node.description» + «IF node.reference !== null» + Reference «node.reference» + «ENDIF» + ''' - def paragraphs(String body) ''' -

          «body»

          + private def listItem(String value) ''' + «IF value !== null && !value.empty» +
        • + «value» +
        • + «ENDIF» ''' - def listItem(String name, String value) ''' + private def listItem(String name, String value) ''' «IF value !== null && !value.empty»
        • - «name» -
            -
          • - «value» -
          • -
          + «name»: «value»
        • «ENDIF» ''' - def dispatch addedByInfo(SchemaNode node) ''' + 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(SchemaPath.create(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 dispatch addedByInfo(SchemaNode node) ''' ''' - def dispatch addedByInfo(DataSchemaNode node) ''' + private def dispatch addedByInfo(DataSchemaNode node) ''' «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF» ''' - def dispatch isAddedBy(SchemaNode node) { + private def dispatch isAddedBy(SchemaNode node) { return false; } - def dispatch isAddedBy(DataSchemaNode node) { + private def dispatch isAddedBy(DataSchemaNode node) { if (node.augmenting || node.addedByUses) { return true } else { @@ -488,17 +1476,25 @@ class GeneratorImpl { } } - def nodeName(SchemaNode node) ''' + 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» ''' - def nodeName(ListSchemaNode node) ''' + private def dispatch nodeName(ListSchemaNode node) ''' «IF node.isAddedBy» - «italic(node.QName.localName)» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo» + «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»