Yang parser refactoring.
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingGeneratorImpl.xtend
index 3630ce973731a56eaaef4e9828fa179518a486f4..e7791257d41dfcb8b57295cf058091655a98884e 100644 (file)
@@ -6,13 +6,21 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
  */
 package org.opendaylight.yangtools.sal.binding.generator.impl;
+\r
+import static com.google.common.base.Preconditions.*;\r
+import static extension org.opendaylight.yangtools.binding.generator.util.Types.*;\r
+import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;\r
+import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.*;\r
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;\r
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
+import java.util.Set;\r
+import java.util.Iterator\r
+import java.util.Collection
 import org.opendaylight.yangtools.binding.generator.util.BindingTypes;
 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
 import org.opendaylight.yangtools.binding.generator.util.Types;
@@ -54,11 +62,6 @@ import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.opendaylight.yangtools.yang.model.util.UnionType;
-import static com.google.common.base.Preconditions.*;
-import static extension org.opendaylight.yangtools.binding.generator.util.Types.*;
-import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;
-import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.*;
-import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
 import org.opendaylight.yangtools.yang.model.api.UsesNode
@@ -66,28 +69,25 @@ import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder
 import org.opendaylight.yangtools.yang.model.api.ModuleImport
 import org.opendaylight.yangtools.yang.binding.DataContainer
-import java.util.Iterator
 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
-import java.util.Collection
-import org.opendaylight.yangtools.yang.model.api.YangNode
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder
 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl
-
 import org.opendaylight.yangtools.yang.common.QName\rimport org.opendaylight.yangtools.yang.binding.BindingMapping
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase
 
-import org.opendaylight.yangtools.yang.common.QName\rimport com.google.common.collect.Sets
-
+import com.google.common.collect.Sets
+import java.net.URI
+import java.util.Date
 
 public class BindingGeneratorImpl implements BindingGenerator {
 
     private final Map<Module, ModuleContext> genCtx = new HashMap()
 
     /**\r
-     * Outter key represents the package name. Outter value represents map of\r
+     * Outer key represents the package name. Outer value represents map of\r
      * all builders in the same package. Inner key represents the schema node\r
      * name (in JAVA class/interface name format). Inner value represents\r
      * instance of builder for schema node specified in key part.\r
@@ -100,7 +100,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private var TypeProvider typeProvider;
 
     /**\r
-     * Holds reference to schema context to resolve data of augmented elemnt\r
+     * Holds reference to schema context to resolve data of augmented element\r
      * when creating augmentation builder\r
      */
     private var SchemaContext schemaContext;
@@ -597,7 +597,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
     /**\r
      * Converts all <b>groupings</b> of the module to the list of\r
      * <code>Type</code> objects. Firstly are groupings sorted according mutual\r
-     * dependencies. At least dependend (indepedent) groupings are in the list\r
+     * dependencies. At least dependent (independent) groupings are in the list\r
      * saved at first positions. For every grouping the record is added to map\r
      * {@link BindingGeneratorImpl#allGroupings allGroupings}\r
      *\r
@@ -640,7 +640,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
     /**\r
      * Tries to find EnumTypeDefinition in <code>typeDefinition</code>. If base\r
      * type of <code>typeDefinition</code> is of the type ExtendedType then this\r
-     * method is recursivelly called with this base type.\r
+     * method is recursively called with this base type.\r
      *\r
      * @param typeDefinition\r
      *            TypeDefinition in which should be EnumTypeDefinition found as\r
@@ -673,7 +673,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            builder\r
      * @param typeBuilder\r
      *            GeneratedTypeBuilder to which will be enum builder assigned\r
-     * @return enumeration builder which contais data from\r
+     * @return enumeration builder which contains data from\r
      *         <code>enumTypeDef</code>\r
      */
     private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, QName enumName,
@@ -720,7 +720,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            string with the name of the package to which the augmentation\r
      *            belongs\r
      * @param augSchema\r
-     *            AugmentationSchema which is contains data about agumentation\r
+     *            AugmentationSchema which is contains data about augmentation\r
      *            (target path, childs...)\r
      * @param module current module\r
      * @param parentUsesNode parent uses node of this augment (can be null if this augment is not defined under uses statement)\r
@@ -739,11 +739,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
             "Augmentation Schema does not contain Target Path (Target Path is NULL).");
 
         processUsesAugments(augSchema, module);
-
-        // EVERY augmented interface will extends Augmentation<T> interface\r
-        // and DataObject interface\r
+\r
         val targetPath = augSchema.targetPath;
-        var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
+        var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);\r
         if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {
             if (parentUsesNode == null) {
                 targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);
@@ -756,6 +754,10 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         module.name);
             }
         }\r
+\r
+        if (targetSchemaNode == null) {\r
+            throw new IllegalArgumentException("augment target not found")\r
+        }\r
 
         if (targetSchemaNode !== null) {
             var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path)
@@ -799,20 +801,30 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
     private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {
         if (!node.augmenting) {
-            return null;
+            return null
         }
 
-        var String currentName = node.QName.localName;
-        var tmpPath = new ArrayList<String>();
-        var YangNode parent = node;
+        var String currentName = node.QName.localName\r
+        var Object currentNode = node
+        var Object parent = node;\r
+        val tmpPath = new ArrayList<String>()\r
+        val tmpTree = new ArrayList<SchemaNode>()\r
+
         var AugmentationSchema augment = null;
-        do {
-            parent = (parent as DataSchemaNode).parent;
+        do {\r
+            val SchemaPath sp = (parent as SchemaNode).path\r
+            val List<QName> names = sp.path\r
+            val List<QName> newNames = new ArrayList(names)\r
+            newNames.remove(newNames.size - 1)\r
+            val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)\r
+            parent = findDataSchemaNode(schemaContext, newSp)\r
             if (parent instanceof AugmentationTarget) {
-                tmpPath.add(currentName);
+                tmpPath.add(currentName);\r
+                tmpTree.add(currentNode as SchemaNode)\r
                 augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);
                 if (augment == null) {
-                    currentName = (parent as DataSchemaNode).QName.localName;
+                    currentName = (parent as DataSchemaNode).QName.localName;\r
+                    currentNode = parent
                 }
             }
         } while ((parent as DataSchemaNode).augmenting && augment == null);
@@ -820,7 +832,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (augment == null) {
             return null;
         } else {
-            Collections.reverse(tmpPath);
+            Collections.reverse(tmpPath);\r
+            Collections.reverse(tmpTree);
             var Object actualParent = augment;
             var DataSchemaNode result = null;
             for (name : tmpPath) {
@@ -835,8 +848,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 }
             }
 
-            if (result.addedByUses) {
-                result = findCorrectTargetFromGrouping(result);
+            if (result.addedByUses) {\r
+                result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree);
             }
 
             return result;
@@ -851,76 +864,138 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
         return null;
     }
-
-    private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {
-        if (node.path.path.size == 1) {
-
+\r
+    private def DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node) {\r
+        if (node.path.path.size == 1) {\r
             // uses is under module statement\r
-            val Module m = findParentModule(schemaContext, node);
-            var DataSchemaNode result = null;
-            for (u : m.uses) {
-                var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
-                if (!(targetGrouping instanceof GroupingDefinition)) {
-                    throw new IllegalArgumentException("Failed to generate code for augment in " + u);
-                }
-                var gr = targetGrouping as GroupingDefinition;
-                result = gr.getDataChildByName(node.QName.localName);
-            }
-            if (result == null) {
-                throw new IllegalArgumentException("Failed to generate code for augment");
-            }
-            return result;
-        } else {
-            var DataSchemaNode result = null;
-            var String currentName = node.QName.localName;
-            var tmpPath = new ArrayList<String>();
-            var YangNode parent = node.parent;
-            do {
-                tmpPath.add(currentName);
-                val dataNodeParent = parent as DataNodeContainer;
-                for (u : dataNodeParent.uses) {
+            val Module m = findParentModule(schemaContext, node);\r
+            var DataSchemaNode result = null;\r
+            for (u : m.uses) {\r
+                var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);\r
+                if (!(targetGrouping instanceof GroupingDefinition)) {\r
+                    throw new IllegalArgumentException("Failed to generate code for augment in " + u);\r
+                }\r
+                var gr = targetGrouping as GroupingDefinition;\r
+                result = gr.getDataChildByName(node.QName.localName);\r
+            }\r
+            if (result == null) {\r
+                throw new IllegalArgumentException("Failed to generate code for augment")\r
+            }\r
+            return result\r
+        } else {\r
+            var DataSchemaNode result = null;\r
+            var String currentName = node.QName.localName\r
+            var tmpPath = new ArrayList<String>()\r
+            var Object parent = null\r
+
+            val SchemaPath sp = node.path
+            val List<QName> names = sp.path
+            val List<QName> newNames = new ArrayList(names)
+            newNames.remove(newNames.size - 1)
+            val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)
+            parent = findDataSchemaNode(schemaContext, newSp)
+\r
+            do {\r
+                tmpPath.add(currentName);\r
+                val dataNodeParent = parent as DataNodeContainer;\r
+                for (u : dataNodeParent.uses) {\r
                     if (result == null) {\r
-                        var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path);
-                        if (!(targetGrouping instanceof GroupingDefinition)) {
-                            throw new IllegalArgumentException("Failed to generate code for augment in " + u);
-                        }
-                        var gr = targetGrouping as GroupingDefinition;
-                        result = gr.getDataChildByName(currentName);\r
-                    }
-                }
+                        result = getResultFromUses(u, currentName)\r
+                    }\r
+                }\r
                 if (result == null) {
-                    currentName = (parent as SchemaNode).QName.localName;
+                    currentName = (parent as SchemaNode).QName.localName
                     if (parent instanceof DataSchemaNode) {
-                        parent = (parent as DataSchemaNode).parent;
+                        val SchemaPath nodeSp = (parent as DataSchemaNode).path
+                        val List<QName> nodeNames = nodeSp.path
+                        val List<QName> nodeNewNames = new ArrayList(nodeNames)
+                        nodeNewNames.remove(nodeNewNames.size - 1)
+                        if (nodeNewNames.empty) {
+                            parent = getParentModule(parent as SchemaNode)
+                        } else {
+                            val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute)
+                            parent = findDataSchemaNode(schemaContext, nodeNewSp)
+                        }
                     } else {
-                        parent = (parent as DataNodeContainer).parent;
+                        throw new IllegalArgumentException("Failed to generate code for augment")
                     }
-                }
-            } while (result == null && !(parent instanceof Module));
+                }\r
+            } while (result == null && !(parent instanceof Module));\r
+\r
+            if (result != null) {\r
+                result = getTargetNode(tmpPath, result)\r
+            }\r
+            return result;\r
+        }\r
+    }\r
+\r
+    private def DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node, AugmentationSchema parentNode,
+        List<SchemaNode> dataTree) {\r
+\r
+        var DataSchemaNode result = null;
+        var String currentName = node.QName.localName
+        var tmpPath = new ArrayList<String>()\r
+        tmpPath.add(currentName)\r
+        var int i = 1;\r
+        var Object parent = null
+\r
+        do {\r
+            if (dataTree.size < 2 || dataTree.size == i) {
+                parent = parentNode
+            } else {
+                parent = dataTree.get(dataTree.size - (i+1))
+                tmpPath.add((parent as SchemaNode).QName.localName);
+            }\r
 
-            if (result != null) {
-                if (tmpPath.size == 1) {\r
-                    if (result != null && result.addedByUses) {\r
-                        result = findOriginal(result);\r
-                    }
-                    return result;
-                } else {
-                    var DataSchemaNode newParent = result;
-                    Collections.reverse(tmpPath);
-                    tmpPath.remove(0);
-                    for (name : tmpPath) {
-                        newParent = (newParent as DataNodeContainer).getDataChildByName(name);
-                    }\r
-                    if (newParent != null && newParent.addedByUses) {\r
-                        newParent = findOriginal(newParent);\r
-                    }
-                    return newParent;
+            val dataNodeParent = parent as DataNodeContainer;
+            for (u : dataNodeParent.uses) {
+                if (result == null) {\r
+                    result = getResultFromUses(u, currentName)
                 }
             }
-
+            if (result == null) {
+                i = i + 1\r
+                currentName = (parent as SchemaNode).QName.localName
+            }
+        } while (result == null);
+\r
+        if (result != null) {
+            result = getTargetNode(tmpPath, result)\r
+        }
+        return result;
+    }\r
+\r
+    private def getResultFromUses(UsesNode u, String currentName) {
+        var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, u.groupingPath.path)
+        if (!(targetGrouping instanceof GroupingDefinition)) {
+            throw new IllegalArgumentException("Failed to generate code for augment in " + u)
+        }
+        var gr = targetGrouping as GroupingDefinition
+        return gr.getDataChildByName(currentName)
+    }\r
+\r
+    private def getTargetNode(List<String> tmpPath, DataSchemaNode node) {
+        var DataSchemaNode result = node
+        if (tmpPath.size == 1) {
+            if (result != null && result.addedByUses) {
+                result = findOriginal(result);
+            }
             return result;
+        } else {
+            var DataSchemaNode newParent = result;
+            Collections.reverse(tmpPath);
+
+            tmpPath.remove(0);
+            for (name : tmpPath) {
+                newParent = (newParent as DataNodeContainer).getDataChildByName(name);
+            }
+            if (newParent != null && newParent.addedByUses) {
+                newParent = findOriginal(newParent);
+            }
+            return newParent;
         }
-    }
+    }\r
+
 
     /**\r
      * Convenient method to find node added by uses statement.\r
@@ -1217,7 +1292,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 genCtx.get(module).addCaseType(caseNode.path, caseTypeBuilder)
                 val Set<DataSchemaNode> caseChildNodes = caseNode.childNodes
                 if (caseChildNodes !== null) {
-                    val parentNode = choiceNode.parent
+                    var Object parentNode = null\r
+                    val SchemaPath nodeSp = choiceNode.path\r
+                    val List<QName> nodeNames = nodeSp.path\r
+                    val List<QName> nodeNewNames = new ArrayList(nodeNames)\r
+                    nodeNewNames.remove(nodeNewNames.size - 1)\r
+                    val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute)\r
+                    parentNode = findDataSchemaNode(schemaContext, nodeNewSp)\r
+
                     var SchemaNode parent
                     if (parentNode instanceof AugmentationSchema) {
                         val augSchema = parentNode as AugmentationSchema;
@@ -1234,7 +1316,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         }
                         parent = targetSchemaNode
                     } else {
-                        parent = choiceNode.parent as SchemaNode
+                        val SchemaPath sp = choiceNode.path\r
+                        val List<QName> names = sp.path\r
+                        val List<QName> newNames = new ArrayList(names)\r
+                        newNames.remove(newNames.size - 1)\r
+                        val SchemaPath newSp = new SchemaPath(newNames, sp.absolute)\r
+                        parent = findDataSchemaNode(schemaContext, newSp)\r
                     }
                     var GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.path)
                     resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes)
@@ -1282,7 +1369,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 val caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
                 caseTypeBuilder.addImplementsType(targetType);
 
-                val SchemaNode parent = targetNode.parent as SchemaNode;
+                var SchemaNode parent = null\r
+                val SchemaPath nodeSp = targetNode.path\r
+                val List<QName> nodeNames = nodeSp.path\r
+                val List<QName> nodeNewNames = new ArrayList(nodeNames)\r
+                nodeNewNames.remove(nodeNewNames.size - 1)\r
+                val SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.absolute)\r
+                parent = findDataSchemaNode(schemaContext, nodeNewSp)\r
+
                 var GeneratedTypeBuilder childOfType = null;
                 if (parent instanceof Module) {
                     childOfType = genCtx.get(parent as Module).moduleNode
@@ -1598,7 +1692,6 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode,
         Type parent) {
         val it = addRawInterfaceDefinition(packageName, schemaNode, "");\r
-        val qname = schemaNode.QName;
         qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName);\r
         if (parent === null) {
             addImplementsType(DATA_OBJECT);
@@ -1650,7 +1743,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>schemaNode</code> equals null</li>\r
      *             <li>if <code>packageName</code> equals null</li>\r
      *             <li>if Q name of schema node is null</li>\r
-     *             <li>if schema node name is nul</li>\r
+     *             <li>if schema node name is null</li>\r
      *             </ul>\r
      *\r
      */
@@ -1685,13 +1778,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
     }
 
     /**\r
-     * Creates the name of the getter method from <code>localName</code>.\r
+     * Creates the name of the getter method from <code>methodName</code>.\r
      *\r
-     * @param localName\r
+     * @param methodName\r
      *            string with the name of the getter method\r
      * @param returnType return type\r
      * @return string with the name of the getter method for\r
-     *         <code>localName</code> in JAVA method format\r
+     *         <code>methodName</code> in JAVA method format\r
      */
     public static def String getterMethodName(String localName, Type returnType) {
         val method = new StringBuilder();
@@ -1903,7 +1996,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * Adds the implemented types to type builder.\r
      *\r
      * The method passes through the list of <i>uses</i> in\r
-     * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding\r
+     * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding\r
      * generated type from {@link BindingGeneratorImpl#allGroupings\r
      * allGroupings} which is added as <i>implements type</i> to\r
      * <code>builder</code>\r
@@ -1959,8 +2052,15 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null
     }
 \r
+    private def Module getParentModule(SchemaNode node) {\r
+        val QName qname = node.getPath().getPath().get(0);\r
+        val URI namespace = qname.getNamespace();\r
+        val Date revision = qname.getRevision();\r
+        return schemaContext.findModuleByNamespaceAndRevision(namespace, revision);\r
+    }\r
 \r
     public def getModuleContexts() {\r
         genCtx;\r
-    }
+    }\r
+\r
 }