Migrate getDataChildByName() users
[mdsal.git] / binding / maven-sal-api-gen-plugin / src / main / java / org / opendaylight / mdsal / binding / yang / unified / doc / generator / GeneratorImpl.xtend
index 31f615247bbc059f06a8b187c1bc0330605593ad..ec0b087204421e1875be7db0ac0159eec48eff2a 100644 (file)
@@ -7,13 +7,12 @@
  */
 package org.opendaylight.mdsal.binding.yang.unified.doc.generator
 
-import com.google.common.collect.Iterables
 import java.io.BufferedWriter
 import java.io.File
 import java.io.IOException
 import java.io.OutputStreamWriter
 import java.nio.charset.StandardCharsets
-import java.text.SimpleDateFormat
+import java.nio.file.Files
 import java.util.ArrayList
 import java.util.Collection
 import java.util.HashMap
@@ -21,17 +20,21 @@ 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.AnyxmlSchemaNode
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
-import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode
+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.EffectiveModelContext
+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
@@ -39,66 +42,70 @@ 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.IntegerTypeDefinition
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute
 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint
+import org.opendaylight.yangtools.yang.model.api.type.LengthRestrictedTypeDefinition
 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.type.RangeRestrictedTypeDefinition
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.sonatype.plexus.build.incremental.BuildContext
-import org.sonatype.plexus.build.incremental.DefaultBuildContext
-import com.google.common.collect.Lists
 
+@SuppressModernizer
 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<String, String> imports = new HashMap();
-    var SchemaContext ctx;
-    
+    var Module currentModule;
+    var EffectiveModelContext ctx;
+    var File path
+
     StringBuilder augmentChildNodesAsString
-    
+
     DataSchemaNode lastNodeInTargetPath = null
 
-    def generate(SchemaContext context, File targetPath, Set<Module> modulesToGen) throws IOException {
+    def generate(BuildContext buildContext, EffectiveModelContext context, File targetPath, Set<Module> modulesToGen)
+            throws IOException {
         path = targetPath;
-        path.mkdirs();
+        Files.createDirectories(path.getParentFile().toPath())
         val it = new HashSet;
         for (module : modulesToGen) {
-            add(generateDocumentation(module, context));
+            add(generateDocumentation(buildContext, module, context));
         }
         return it;
     }
 
-    def generateDocumentation(Module module, SchemaContext ctx) {
+    def generateDocumentation(BuildContext buildContext, Module module, EffectiveModelContext ctx) {
         val destination = new File(path, '''«module.name».html''')
         this.ctx = ctx;
         module.imports.forEach[importModule | this.imports.put(importModule.prefix, importModule.moduleName)]
+        var OutputStreamWriter fw
+        var BufferedWriter bw
         try {
-            val fw = new OutputStreamWriter(CTX.newFileOutputStream(destination), StandardCharsets.UTF_8)
-            val bw = new BufferedWriter(fw)
+            fw = new OutputStreamWriter(buildContext.newFileOutputStream(destination), StandardCharsets.UTF_8)
+            bw = new BufferedWriter(fw)
             currentModule = module;
             bw.append(generate(module, ctx));
-            bw.close();
-            fw.close();
         } catch (IOException e) {
-            LOG.error(e.getMessage());
+            LOG.error("Failed to emit file {}", destination, e);
+        } finally {
+            if (bw !== null) {
+                bw.close();
+            }
+            if (fw !== null) {
+                fw.close();
+            }
         }
         return destination;
     }
 
-    def generate(Module module, SchemaContext ctx) '''
+    def generate(Module module, EffectiveModelContext ctx) '''
         <!DOCTYPE html>
         <html lang="en">
           <head>
@@ -110,7 +117,7 @@ class GeneratorImpl {
         </html>
     '''
 
-    def body(Module module, SchemaContext ctx) '''
+    def body(Module module, EffectiveModelContext ctx) '''
         «header(module)»
 
         «typeDefinitionsSummary(module)»
@@ -147,7 +154,7 @@ class GeneratorImpl {
 
 
     private def typeDefinitionsSummary(Module module) {
-        val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+        val Collection<? extends TypeDefinition<?>> typedefs = module.typeDefinitions
         if (typedefs.empty) {
             return '';
         }
@@ -175,7 +182,7 @@ class GeneratorImpl {
     }
 
     def typeDefinitions(Module module) {
-        val Set<TypeDefinition<?>> typedefs = module.typeDefinitions
+        val Collection<? extends TypeDefinition<?>> typedefs = module.typeDefinitions
         if (typedefs.empty) {
             return '';
         }
@@ -299,18 +306,18 @@ class GeneratorImpl {
         '''
     }
 
-    def augmentations(Module module, SchemaContext context) {
+    def augmentations(Module module, EffectiveModelContext context) {
         if (module.augmentations.empty) {
             return '';
         }
         return '''
             <h2>Augmentations</h2>
-            
+
             <ul>
             «FOR augment : module.augmentations»
                 <li>
                     <h3 id="«schemaPathToString(module, augment.targetPath, context, augment)»">
-                    Target [«typeAnchorLink(augment.targetPath,schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
+                    Target [«typeAnchorLink(augment.targetPath.asSchemaPath, schemaPathToString(module, augment.targetPath, context, augment))»]</h3>
                     «augment.description»
                         Status: «strong(String.valueOf(augment.status))»
                     «IF augment.reference !== null»
@@ -322,7 +329,7 @@ class GeneratorImpl {
                     «FOR childNode : augment.childNodes»
                         «childNode.printSchemaNodeInfo»
                     «ENDFOR»
-                    
+
                     <h3>Example</h3>
                     «createAugmentChildNodesAsString(new ArrayList(augment.childNodes))»
                     «printNodeChildren(parseTargetPath(augment.targetPath))»
@@ -331,19 +338,19 @@ class GeneratorImpl {
             </ul>
         '''
     }
-    
+
     private def createAugmentChildNodesAsString(List<DataSchemaNode> childNodes) {
         augmentChildNodesAsString = new StringBuilder();
         augmentChildNodesAsString.append(printNodeChildren(childNodes))
         return ''
     }
-    
-    private def parseTargetPath(SchemaPath path) {
-        val List<DataSchemaNode> nodes = new ArrayList<DataSchemaNode>();
-        for (QName pathElement : path.pathFromRoot) {
-            val module = ctx.findModuleByNamespaceAndRevision(pathElement.namespace, pathElement.revision);
-            if (module !== null) {
-                var foundNode = module.getDataChildByName(pathElement)
+
+    private def parseTargetPath(SchemaNodeIdentifier path) {
+        val nodes = new ArrayList<DataSchemaNode>();
+        for (QName pathElement : path.nodeIdentifiers) {
+            val module = ctx.findModule(pathElement.module)
+            if (module.isPresent) {
+                var foundNode = module.get.dataChildByName(pathElement)
                 if (foundNode === null) {
                     val child = nodes.last
                     if (child instanceof DataNodeContainer) {
@@ -356,18 +363,18 @@ class GeneratorImpl {
                 }
             }
         }
-        if(! nodes.empty) {
+        if (!nodes.empty) {
             lastNodeInTargetPath = nodes.get(nodes.size() - 1)
         }
-        
-        val List<DataSchemaNode> targetPathNodes = new ArrayList<DataSchemaNode>();
+
+        val targetPathNodes = new ArrayList<DataSchemaNode>();
         targetPathNodes.add(lastNodeInTargetPath)
-        
+
         return targetPathNodes
     }
-    
-    private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable<DataSchemaNode> childNodes) {
-        for(child : childNodes) {
+
+    private def DataSchemaNode findNodeInChildNodes(QName findingNode, Iterable<? extends DataSchemaNode> childNodes) {
+        for (child : childNodes) {
             if (child.QName.equals(findingNode))
                 return child;
         }
@@ -384,31 +391,31 @@ class GeneratorImpl {
             }
         }
     }
-    
+
     private def printNodeChildren(List<DataSchemaNode> childNodes) {
         if (childNodes.empty) {
             return ''
         }
-        
-        return 
+
+        return
         '''
         <pre>
         «printAugmentedNode(childNodes.get(0))»
         </pre>
         '''
     }
-    
+
     private def CharSequence printAugmentedNode(DataSchemaNode child) {
-        
-        if(child instanceof ChoiceCaseNode)
+
+        if(child instanceof CaseSchemaNode)
             return ''
-            
+
         return
         '''
         «IF child instanceof ContainerSchemaNode»
             «printContainerNode(child)»
         «ENDIF»
-        «IF child instanceof AnyXmlSchemaNode»
+        «IF child instanceof AnyxmlSchemaNode»
             «printAnyXmlNode(child)»
         «ENDIF»
         «IF child instanceof LeafSchemaNode»
@@ -425,16 +432,16 @@ class GeneratorImpl {
         «ENDIF»
         '''
     }
-    
+
     private def printChoiceNode(ChoiceSchemaNode child) {
-        val List<ChoiceCaseNode> cases = new ArrayList(child.cases);
-        if(!cases.empty) {
-            val ChoiceCaseNode aCase = cases.get(0)
-            for(caseChildNode : aCase.childNodes)
+        val cases = new ArrayList(child.cases)
+        if (!cases.empty) {
+            val CaseSchemaNode aCase = cases.get(0)
+            for (caseChildNode : aCase.childNodes)
                 printAugmentedNode(caseChildNode)
         }
     }
-    
+
     private def printListNode(ListSchemaNode listNode) {
         return
         '''
@@ -445,7 +452,7 @@ class GeneratorImpl {
             &lt;/«listNode.QName.localName»&gt;
         '''
     }
-    
+
     private def printContainerNode(ContainerSchemaNode containerNode) {
         return
         '''
@@ -456,7 +463,7 @@ class GeneratorImpl {
             &lt;/«containerNode.QName.localName»&gt;
         '''
     }
-    
+
     private def printLeafListNode(LeafListSchemaNode leafListNode) {
         return
         '''
@@ -465,22 +472,22 @@ class GeneratorImpl {
             &lt;«leafListNode.QName.localName»&gt;. . .&lt;/«leafListNode.QName.localName»&gt;
         '''
     }
-    
-    private def printAnyXmlNode(AnyXmlSchemaNode anyXmlNode) {
-        return 
+
+    private def printAnyXmlNode(AnyxmlSchemaNode anyXmlNode) {
+        return
         '''
             &lt;«anyXmlNode.QName.localName»&gt;. . .&lt;/«anyXmlNode.QName.localName»&gt;
         '''
     }
-    
+
     private def printLeafNode(LeafSchemaNode leafNode) {
-        return 
+        return
         '''
             &lt;«leafNode.QName.localName»&gt;. . .&lt;/«leafNode.QName.localName»&gt;
         '''
     }
 
-    private def augmentationsSummary(Module module, SchemaContext context) {
+    private def augmentationsSummary(Module module, EffectiveModelContext context) {
         if (module.augmentations.empty) {
             return '';
         }
@@ -507,7 +514,7 @@ class GeneratorImpl {
     }
 
     def notifications(Module module) {
-        val Set<NotificationDefinition> notificationdefs = module.notifications
+        val Collection<? extends NotificationDefinition> notificationdefs = module.notifications
         if (notificationdefs.empty) {
             return '';
         }
@@ -719,8 +726,10 @@ class GeneratorImpl {
                 <td>«module.namespace»</td>
             </tr>
             <tr>
+                «IF module.revision.isPresent»
                 <td>«strong("revision")»</td>
-                <td>«REVISION_FORMAT.format(module.revision)»</td>
+                <td>«module.revision.get.toString»</td>
+                «ENDIF»
             </tr>
             <tr>
                 <td>«strong("description")»</td>
@@ -732,7 +741,7 @@ class GeneratorImpl {
             </tr>
             <tr>
                 «FOR imp : module.imports BEFORE '''<td>«strong("imports")»</td><td>''' AFTER '''</td>'''»
-                    «imp.prefix»:«imp.moduleName»«IF imp.revision !== null» «REVISION_FORMAT.format(imp.revision)»«ENDIF»;
+                    «imp.prefix»:«imp.moduleName»«IF imp.revision.isPresent» «imp.revision.get.toString»«ENDIF»;
                 «ENDFOR»
             </tr>
         </table>
@@ -755,12 +764,12 @@ class GeneratorImpl {
         «module.childNodes.treeSet(YangInstanceIdentifier.builder.build())»
     '''
 
-    private def dispatch CharSequence tree(ChoiceSchemaNode node,YangInstanceIdentifier path) '''
+    private def CharSequence tree(ChoiceSchemaNode node, YangInstanceIdentifier path) '''
         «node.nodeName» (choice)
-        «casesTree(node.cases,path)»
+        «casesTree(node.cases, path)»
     '''
 
-    def casesTree(Set<ChoiceCaseNode> nodes,YangInstanceIdentifier path) '''
+    def casesTree(Collection<? extends CaseSchemaNode> nodes, YangInstanceIdentifier path) '''
         <ul>
         «FOR node : nodes»
             <li>
@@ -771,17 +780,24 @@ class GeneratorImpl {
         </ul>
     '''
 
-    private def dispatch CharSequence tree(DataSchemaNode node,YangInstanceIdentifier path) '''
-        «node.nodeName»
-    '''
+    private def CharSequence tree(DataSchemaNode node, YangInstanceIdentifier path) {
+        if (node instanceof ChoiceSchemaNode) {
+            return tree(node, path)
+        } else if (node instanceof ListSchemaNode) {
+            return tree(node, path)
+        } else if (node instanceof ContainerSchemaNode) {
+            return tree(node, path)
+        }
+        return node.nodeName
+    }
 
-    private def dispatch CharSequence tree(ListSchemaNode node,YangInstanceIdentifier path) '''
+    private def 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) '''
+    private def CharSequence tree(ContainerSchemaNode node,YangInstanceIdentifier path) '''
         «val newPath = path.append(node)»
         «localLink(newPath,node.nodeName)»
         «node.childNodes.treeSet(newPath)»
@@ -808,8 +824,7 @@ class GeneratorImpl {
                 «ENDFOR»
                 </ul>
                 <ul>
-                «val Set<TypeDefinition<?>> typeDefinitions = dataNode.typeDefinitions»
-                «FOR typeDef : typeDefinitions»
+                «FOR typeDef : dataNode.typeDefinitions»
                     «typeDef.restrictions»
                 «ENDFOR»
                 </ul>
@@ -830,7 +845,7 @@ class GeneratorImpl {
 
     def String typeAnchorLink(SchemaPath path, CharSequence text) {
         if(path !== null) {
-            val lastElement = Iterables.getLast(path.pathFromRoot)
+            val lastElement = path.lastComponent
             val ns = lastElement.namespace
             if (ns == this.currentModule.namespace) {
                 return '''<a href="#«path.schemaPathToId»">«text»</a>'''
@@ -847,14 +862,16 @@ class GeneratorImpl {
             return '''
                 «printInfo(node, "leaf")»
                 «listItem("type", typeAnchorLink(node.type?.path, node.type.QName.localName))»
-                «listItem("units", node.units
-                «listItem("default", node.^default
+                «listItem("units", node.type.units.orElse(null)
+                «listItem("default", node.type.defaultValue.map([ Object o | o.toString]).orElse(null)
                 </ul>
             '''
         } else if(node instanceof LeafListSchemaNode) {
             return '''
                 «printInfo(node, "leaf-list")»
-                «listItem("type", node.type?.QName.localName)»
+                «IF node.type !== null»
+                    «listItem("type", node.type.QName.localName)»
+                «ENDIF»
                 </ul>
             '''
         } else if(node instanceof ListSchemaNode) {
@@ -868,13 +885,13 @@ class GeneratorImpl {
         } else if(node instanceof ChoiceSchemaNode) {
             return '''
                 «printInfo(node, "choice")»
-                «listItem("default case", node.defaultCase)»
+                «listItem("default case", node.defaultCase.map([ CaseSchemaNode n | n.getQName.localName]).orElse(null)
                 «FOR caseNode : node.cases»
                     «caseNode.printSchemaNodeInfo»
                 «ENDFOR»
                 </ul>
             '''
-        } else if(node instanceof ChoiceCaseNode) {
+        } else if(node instanceof CaseSchemaNode) {
             return '''
                 «printInfo(node, "case")»
                 </ul>
@@ -884,7 +901,7 @@ class GeneratorImpl {
                 «printInfo(node, "container")»
                 </ul>
             '''
-        } else if(node instanceof AnyXmlSchemaNode) {
+        } else if(node instanceof AnyxmlSchemaNode) {
             return '''
                 «printInfo(node, "anyxml")»
                 </ul>
@@ -906,19 +923,26 @@ class GeneratorImpl {
                 «strong(listItem(nodeType, node.QName.localName))»
             «ENDIF»
             <ul>
-            «listItem("description", node.description)»
-            «listItem("reference", node.reference)»
+            «listItem("description", node.description.orElse(null)
+            «listItem("reference", node.reference.orElse(null)
             «IF node instanceof DataSchemaNode»
-                «listItem("when condition", node.constraints.whenCondition?.toString)»
-                «listItem("min elements", node.constraints.minElements?.toString)»
-                «listItem("max elements", node.constraints.maxElements?.toString)»
+                «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)))»
+            «strong(listItem("uses", typeAnchorLink(usesNode.sourceGrouping.path, usesNode.sourceGrouping.path.pathTowardsRoot.iterator.next.localName)))»
             <ul>
             <li>refines:
                 <ul>
@@ -928,7 +952,7 @@ class GeneratorImpl {
                 </ul>
             </li>
             «FOR augment : usesNode.augmentations»
-                «typeAnchorLink(augment.targetPath,schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
+                «typeAnchorLink(augment.targetPath.asSchemaPath, schemaPathToString(currentModule, augment.targetPath, ctx, augment))»
             «ENDFOR»
             </ul>
         '''
@@ -940,12 +964,12 @@ class GeneratorImpl {
         '''
     }
 
-    def CharSequence printChildren(Iterable<DataSchemaNode> nodes, int level, YangInstanceIdentifier path) {
-        val anyxmlNodes = nodes.filter(AnyXmlSchemaNode)
+    def CharSequence printChildren(Iterable<? extends DataSchemaNode> 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(ChoiceCaseNode)
+        val cases = nodes.filter(CaseSchemaNode)
         val containers = nodes.filter(ContainerSchemaNode)
         val lists = nodes.filter(ListSchemaNode)
         return '''
@@ -990,13 +1014,13 @@ class GeneratorImpl {
         '''
     }
 
-    def CharSequence xmlExample(Iterable<DataSchemaNode> nodes, QName name,YangInstanceIdentifier path) '''
+    def CharSequence xmlExample(Iterable<? extends DataSchemaNode> nodes, QName name, YangInstanceIdentifier path) '''
     <pre>
         «xmlExampleTag(name,nodes.xmplExampleTags(path))»
     </pre>
     '''
 
-    def CharSequence xmplExampleTags(Iterable<DataSchemaNode> nodes, YangInstanceIdentifier identifier) '''
+    def CharSequence xmplExampleTags(Iterable<? extends DataSchemaNode> nodes, YangInstanceIdentifier identifier) '''
         <!-- Child nodes -->
         «FOR node : nodes»
         <!-- «node.QName.localName» -->
@@ -1005,32 +1029,31 @@ class GeneratorImpl {
 
     '''
 
-    private def dispatch CharSequence asXmlExampleTag(LeafSchemaNode node, YangInstanceIdentifier identifier) '''
-        «node.QName.xmlExampleTag("...")»
-    '''
-
-    private def dispatch CharSequence asXmlExampleTag(LeafListSchemaNode node, YangInstanceIdentifier identifier) '''
-        &lt!-- This node could appear multiple times --&gt
-        «node.QName.xmlExampleTag("...")»
-    '''
-
-    private def dispatch CharSequence asXmlExampleTag(ContainerSchemaNode node, YangInstanceIdentifier identifier) '''
-        &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt
-        «node.QName.xmlExampleTag("...")»
-    '''
-
-
-    private def dispatch CharSequence asXmlExampleTag(ListSchemaNode node, YangInstanceIdentifier identifier) '''
-        &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt
-        &lt!-- This node could appear multiple times --&gt
-        «node.QName.xmlExampleTag("...")»
-    '''
-
-
-    private def dispatch CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) '''
-        <!-- noop -->
-    '''
-
+    private def CharSequence asXmlExampleTag(DataSchemaNode node, YangInstanceIdentifier identifier) {
+        if (node instanceof LeafSchemaNode) {
+            return '''«node.QName.xmlExampleTag("...")»'''
+        }
+        if (node instanceof LeafListSchemaNode) {
+            return '''
+            &lt!-- This node could appear multiple times --&gt
+            «node.QName.xmlExampleTag("...")»
+            '''
+        }
+        if (node instanceof ContainerSchemaNode) {
+            return '''
+            &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt
+            «node.QName.xmlExampleTag("...")»
+            '''
+        }
+        if (node instanceof ListSchemaNode) {
+            return '''
+            &lt!-- See «localLink(identifier.append(node),"definition")» for child nodes.  --&gt
+            &lt!-- This node could appear multiple times --&gt
+            «node.QName.xmlExampleTag("...")»
+            '''
+        }
+        return "<!-- noop -->"
+    }
 
     def xmlExampleTag(QName name, CharSequence data) {
         return '''&lt;«name.localName» xmlns="«name.namespace»"&gt;«data»&lt;/«name.localName»&gt;'''
@@ -1045,13 +1068,7 @@ class GeneratorImpl {
         </h«level»>
     '''
 
-
-
-    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) '''
+    private def CharSequence printInfo(ContainerSchemaNode node, int level, YangInstanceIdentifier path) '''
         «val newPath = path.append(node)»
         «header(level,newPath)»
         <dl>
@@ -1063,7 +1080,7 @@ class GeneratorImpl {
         «node.childNodes.printChildren(level,newPath)»
     '''
 
-    private def dispatch CharSequence printInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) '''
+    private def CharSequence printInfo(ListSchemaNode node, int level, YangInstanceIdentifier path) '''
         «val newPath = path.append(node)»
         «header(level,newPath)»
         <dl>
@@ -1075,13 +1092,13 @@ class GeneratorImpl {
         «node.childNodes.printChildren(level,newPath)»
     '''
 
-    private def dispatch CharSequence printInfo(ChoiceSchemaNode node, int level, YangInstanceIdentifier path) '''
+    private def CharSequence printInfo(ChoiceSchemaNode node, int level, YangInstanceIdentifier path) '''
         «val Set<DataSchemaNode> choiceCases = new HashSet(node.cases)»
-        «choiceCases.printChildren(level,path)»
+        «choiceCases.printChildren(level, path)»
     '''
 
-    private def dispatch CharSequence printInfo(ChoiceCaseNode node, int level, YangInstanceIdentifier path) '''
-        «node.childNodes.printChildren(level,path)»
+    private def CharSequence printInfo(CaseSchemaNode node, int level, YangInstanceIdentifier path) '''
+        «node.childNodes.printChildren(level, path)»
     '''
 
 
@@ -1108,12 +1125,12 @@ class GeneratorImpl {
         '''
     }
 
-    def CharSequence printShortInfo(AnyXmlSchemaNode node, int level, YangInstanceIdentifier path) {
+    def CharSequence printShortInfo(AnyxmlSchemaNode node, int level, YangInstanceIdentifier path) {
         return '''
             <li>«strong((node.QName.localName))» (anyxml)
             <ul>
                 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
-                <li>mandatory: «strong(String.valueOf(node.constraints.mandatory))»</li>
+                <li>mandatory: «strong(String.valueOf(node.mandatory))»</li>
             </ul>
             </li>
         '''
@@ -1124,7 +1141,7 @@ class GeneratorImpl {
             <li>«strong((node.QName.localName))» (leaf)
             <ul>
                 <li>configuration data: «strong(String.valueOf(node.configuration))»</li>
-                <li>mandatory: «strong(String.valueOf(node.constraints.mandatory))»</li>
+                <li>mandatory: «strong(String.valueOf(node.mandatory))»</li>
             </ul>
             </li>
         '''
@@ -1163,7 +1180,7 @@ class GeneratorImpl {
             }
         }
 
-        return identifier.node(new NodeIdentifierWithPredicates(node.QName, keyValues));
+        return identifier.node(NodeIdentifierWithPredicates.of(node.QName, keyValues));
     }
 
 
@@ -1181,7 +1198,7 @@ class GeneratorImpl {
             append(arg.nodeType.localName);
             previous = true;
             if(arg instanceof NodeIdentifierWithPredicates) {
-                for(qname : arg.getKeyValues.keySet) {
+                for(qname : arg.keySet) {
                     append("/{");
                     append(qname.localName)
                     append('}')
@@ -1192,19 +1209,20 @@ class GeneratorImpl {
         return it.toString;
     }
 
-    private def String schemaPathToString(Module module, SchemaPath schemaPath, SchemaContext ctx, DataNodeContainer dataNode) {
-            val List<QName> path = Lists.newArrayList(schemaPath.pathFromRoot);
+    private def String schemaPathToString(Module module, SchemaNodeIdentifier schemaPath, EffectiveModelContext ctx,
+            DataNodeContainer dataNode) {
+        val path = schemaPath.nodeIdentifiers
         val StringBuilder pathString = new StringBuilder()
-        if (schemaPath.absolute) {
+        if (schemaPath instanceof Absolute) {
             pathString.append('/')
         }
 
         val QName qname = path.get(0)
-        var Object parent = ctx.findModuleByNamespaceAndRevision(qname.namespace, qname.revision)
+        var Object parent = ctx.findModule(qname.module).orElse(null)
 
         for (name : path) {
             if (parent instanceof DataNodeContainer) {
-                var SchemaNode node = parent.getDataChildByName(name)
+                var SchemaNode node = parent.dataChildByName(name)
                 if (node === null && (parent instanceof Module)) {
                     val notifications = (parent as Module).notifications;
                     for (notification : notifications) {
@@ -1222,14 +1240,14 @@ class GeneratorImpl {
                     }
                 }
 
-                val pathElementModule = ctx.findModuleByNamespaceAndRevision(name.namespace, name.revision)
+                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 ChoiceCaseNode];
+                    val DataSchemaNode caseNode = dataNode.childNodes.findFirst[DataSchemaNode e | e instanceof CaseSchemaNode];
                     if(caseNode !== null) {
                         pathString.append("(case)");
                         pathString.append(caseNode.QName.localName);
@@ -1262,7 +1280,7 @@ class GeneratorImpl {
         «ENDIF»
     '''
 
-    private def CharSequence treeSet(Collection<DataSchemaNode> childNodes, YangInstanceIdentifier path) '''
+    private def CharSequence treeSet(Collection<? extends DataSchemaNode> childNodes, YangInstanceIdentifier path) '''
         «IF childNodes !== null && !childNodes.empty»
             <ul>
             «FOR child : childNodes»
@@ -1285,10 +1303,6 @@ class GeneratorImpl {
         </ul>
     '''
 
-    private def dispatch CharSequence tree(Void obj, YangInstanceIdentifier path) '''
-    '''
-
-
 
     /* #################### RESTRICTIONS #################### */
     private def restrictions(TypeDefinition<?> type) '''
@@ -1297,42 +1311,28 @@ class GeneratorImpl {
         «type.toRange»
     '''
 
-    private def dispatch toLength(TypeDefinition<?> type) {
-    }
-
-    private def dispatch toLength(BinaryTypeDefinition type) '''
-        «type.lengthConstraints.toLengthStmt»
-    '''
-
-    private def dispatch toLength(StringTypeDefinition type) '''
-        «type.lengthConstraints.toLengthStmt»
-    '''
-
-    private def dispatch toRange(TypeDefinition<?> type) {
-    }
-
-    private def dispatch toRange(DecimalTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
-    '''
-
-    private def dispatch toRange(IntegerTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
+    private def toLength(TypeDefinition<?> type) '''
+        «IF type instanceof LengthRestrictedTypeDefinition»
+            «type.lengthConstraint.toLengthStmt»
+        «ENDIF»
     '''
 
-    private def dispatch toRange(UnsignedIntegerTypeDefinition type) '''
-        «type.rangeConstraints.toRangeStmt»
+    private def toRange(TypeDefinition<?> type) '''
+        «IF type instanceof RangeRestrictedTypeDefinition»
+            «type.rangeConstraint.toRangeStmt»
+        «ENDIF»
     '''
 
-    def toLengthStmt(Collection<LengthConstraint> lengths) '''
-        «IF lengths !== null && !lengths.empty»
+    def toLengthStmt(Optional<LengthConstraint> lengths) '''
+        «IF lengths.isPresent»
             «listItem("Length restrictions:")»
             <ul>
-            «FOR length : lengths»
+            «FOR length : lengths.get.allowedRanges.asRanges»
                 <li>
-                «IF length.min == length.max»
-                    «length.min»
+                «IF length.lowerEndpoint == length.upperEndpoint»
+                    «length.lowerEndpoint»
                 «ELSE»
-                    &lt;«length.min», «length.max»&gt;
+                    &lt;«length.lowerEndpoint», «length.upperEndpoint»&gt;
                 «ENDIF»
                 </li>
             «ENDFOR»
@@ -1340,16 +1340,16 @@ class GeneratorImpl {
         «ENDIF»
     '''
 
-    def toRangeStmt(Collection<RangeConstraint> ranges) '''
-        «IF ranges !== null && !ranges.empty»
+    def toRangeStmt(Optional<? extends RangeConstraint<?>> constraint) '''
+        «IF constraint.present»
             «listItem("Range restrictions:")»
             <ul>
-            «FOR range : ranges»
+            «FOR range : constraint.get.allowedRanges.asRanges»
                 <li>
-                «IF range.min == range.max»
-                    «range.min»
+                «IF range.lowerEndpoint == range.upperEndpoint»
+                    «range.lowerEndpoint»
                 «ELSE»
-                    &lt;«range.min», «range.max»&gt;
+                    &lt;«range.lowerEndpoint», «range.upperEndpoint»&gt;
                 «ENDIF»
                 </li>
             «ENDFOR»
@@ -1370,8 +1370,8 @@ class GeneratorImpl {
     private def italic(CharSequence str) '''<i>«str»</i>'''
 
     def CharSequence descAndRefLi(SchemaNode node) '''
-        «listItem("Description", node.description)»
-        «listItem("Reference", node.reference)»
+        «listItem("Description", node.description.orElse(null)
+        «listItem("Reference", node.reference.orElse(null)
     '''
 
     def CharSequence descAndRef(SchemaNode node) '''
@@ -1398,7 +1398,7 @@ class GeneratorImpl {
     '''
 
     private def String nodeSchemaPathToPath(DataSchemaNode node, Map<SchemaPath, DataSchemaNode> childNodes) {
-        if (node instanceof ChoiceSchemaNode || node instanceof ChoiceCaseNode) {
+        if (node instanceof ChoiceSchemaNode || node instanceof CaseSchemaNode) {
             return null
         }
 
@@ -1409,12 +1409,12 @@ class GeneratorImpl {
             result.append('/')
         }
         if (path !== null && !path.empty) {
-            val List<QName> actual = new ArrayList()
+            val 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 ChoiceCaseNode)) {
+                if (!(nodeByPath instanceof ChoiceSchemaNode) && !(nodeByPath instanceof CaseSchemaNode)) {
                     result.append(pathElement.localName)
                     if (i != path.size - 1) {
                         result.append('/')
@@ -1426,34 +1426,38 @@ class GeneratorImpl {
         return result.toString
     }
 
-    private def dispatch addedByInfo(SchemaNode node) '''
-    '''
+    private def addedByInfo(SchemaNode node) {
+        if (node instanceof DataSchemaNode) {
+            return addedByInfo(node)
+        }
+        return ""
+    }
 
-    private def dispatch addedByInfo(DataSchemaNode node) '''
+    private def addedByInfo(DataSchemaNode node) '''
         «IF node.augmenting»(A)«ENDIF»«IF node.addedByUses»(U)«ENDIF»
     '''
 
-    private def dispatch isAddedBy(SchemaNode node) {
-        return false;
+    private def isAddedBy(SchemaNode node) {
+        if (node instanceof DataSchemaNode) {
+            return node.augmenting || node.addedByUses
+        }
+        return false
     }
 
-    private def dispatch isAddedBy(DataSchemaNode node) {
-        if (node.augmenting || node.addedByUses) {
-            return true
-        } else {
-            return false;
+    private def nodeName(SchemaNode node) {
+        if (node instanceof ContainerSchemaNode) {
+            return nodeName(node);
+        } else if (node instanceof ListSchemaNode) {
+            return nodeName(node);
+        }
+        val addedByInfo = node.addedByInfo
+        if (node.isAddedBy) {
+            return '''«italic(node.QName.localName)»«addedByInfo»'''
         }
+        return '''«node.QName.localName»«addedByInfo»'''
     }
 
-    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) '''
+    private def nodeName(ContainerSchemaNode node) '''
         «IF node.isAddedBy»
             «strong(italic(node.QName.localName))»«node.addedByInfo»
         «ELSE»
@@ -1461,7 +1465,7 @@ class GeneratorImpl {
         «ENDIF»
     '''
 
-    private def dispatch nodeName(ListSchemaNode node) '''
+    private def nodeName(ListSchemaNode node) '''
         «IF node.isAddedBy»
             «strong(italic(node.QName.localName))» «IF node.keyDefinition !== null && !node.keyDefinition.empty»«node.listKeys»«ENDIF»«node.addedByInfo»
         «ELSE»