Added getParent() method to DataSchemaNode and DataNodeContainer. Fixed Bugs.
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingGeneratorImpl.xtend
index 1cc3fb6a37d7d641953a01cc80b81af2b44948d7..c0802aecc5be43e0d8d794bc13be66a219966724 100644 (file)
@@ -61,13 +61,15 @@ import static org.opendaylight.yangtools.binding.generator.util.BindingGenerator
 import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.*;\r
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;\r
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort\r
-import org.opendaylight.yangtools.yang.model.util.ExtendedType;\rimport org.opendaylight.yangtools.yang.common.QName
-import org.opendaylight.yangtools.yang.model.api.UsesNode
-import java.util.HashSet
-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 org.opendaylight.yangtools.yang.model.util.ExtendedType;\r
+import org.opendaylight.yangtools.yang.model.api.UsesNode\r
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext\r
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.AnnotationTypeBuilder\r
+import org.opendaylight.yangtools.yang.model.api.ModuleImport\r
+import org.opendaylight.yangtools.yang.binding.DataContainer\rimport java.util.Iterator
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget
+import java.util.Collection
+import org.opendaylight.yangtools.yang.model.api.YangNode
 
 public class BindingGeneratorImpl implements BindingGenerator {\r
     /**\r
@@ -225,7 +227,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private def List<Type> allTypeDefinitionsToGenTypes(Module module) {\r
         checkArgument(module !== null, "Module reference cannot be NULL.");\r
         checkArgument(module.name !== null, "Module name cannot be NULL.");\r
-        val Set<TypeDefinition<?>> typeDefinitions = module.typeDefinitions;\r
+        val it = new DataNodeIterator(module);\r
+        val List<TypeDefinition<?>> typeDefinitions = it.allTypedefs;\r
         checkState(typeDefinitions !== null, '''Type Definitions for module «module.name» cannot be NULL.''');\r
 \r
         val List<Type> generatedTypes = new ArrayList();\r
@@ -284,7 +287,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 \r
         for (usesNode : node.uses) {\r
             for (augment : usesNode.augmentations) {\r
-                result.addAll(augmentationToGenTypes(basePackageName, augment, module, true));\r
+                result.addAll(augmentationToGenTypes(basePackageName, augment, module, usesNode));\r
                 result.addAll(processUsesAugments(augment, module));\r
             }\r
         }\r
@@ -433,7 +436,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         val basePackageName = moduleNamespaceToPackageName(module);\r
         val List<AugmentationSchema> augmentations = resolveAugmentations(module);\r
         for (augment : augmentations) {\r
-            generatedTypes.addAll(augmentationToGenTypes(basePackageName, augment, module, false));\r
+            generatedTypes.addAll(augmentationToGenTypes(basePackageName, augment, module, null));\r
         }\r
         return generatedTypes;\r
     }\r
@@ -916,90 +919,225 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if target path of <code>augSchema</code> equals null</li>\r
      *             </ul>\r
      */\r
-    private def List<Type> augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module, boolean addedByUses) {\r
-        checkArgument(augmentPackageName !== null, "Package Name cannot be NULL.");\r
-        checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL.");\r
-        checkState(augSchema.targetPath !== null,\r
-            "Augmentation Schema does not contain Target Path (Target Path is NULL).");\r
-        val List<Type> genTypes = new ArrayList();\r
-        genTypes.addAll(processUsesAugments(augSchema, module));\r
-\r
+    private def List<Type> augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module,
+        UsesNode parentUsesNode) {
+        checkArgument(augmentPackageName !== null, "Package Name cannot be NULL.");
+        checkArgument(augSchema !== null, "Augmentation Schema cannot be NULL.");
+        checkState(augSchema.targetPath !== null,
+            "Augmentation Schema does not contain Target Path (Target Path is NULL).");
+        val List<Type> genTypes = new ArrayList();
+        genTypes.addAll(processUsesAugments(augSchema, module));
+
         // EVERY augmented interface will extends Augmentation<T> interface\r
         // and DataObject interface!!!\r
-        val targetPath = augSchema.targetPath;\r
-        var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);\r
+        val targetPath = augSchema.targetPath;
+        var targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
         if (targetSchemaNode instanceof DataSchemaNode && (targetSchemaNode as DataSchemaNode).isAddedByUses()) {\r
-                       targetSchemaNode = findOriginalTargetFromGrouping(targetPath, module, targetSchemaNode as DataSchemaNode);\r
-        }\r
-\r
-        if(targetSchemaNode !== null) {\r
-            var targetType = yangToJavaMapping.get(targetSchemaNode.path);\r
-            if(targetType == null) {\r
-\r
+            if (parentUsesNode == null) {\r
+                targetSchemaNode = findOriginal(targetSchemaNode as DataSchemaNode);\r
+            } else {\r
+                targetSchemaNode = findOriginalTargetFromGrouping(targetSchemaNode.QName.localName, parentUsesNode);\r
+            }\r
+            if (targetSchemaNode == null) {\r
+                throw new NullPointerException(\r
+                    "Failed to find target node from grouping for augmentation " + augSchema + " in module " + module.name);\r
+            }
+        }
+\r
+        if (targetSchemaNode !== null) {
+            var targetType = yangToJavaMapping.get(targetSchemaNode.path);
+            if (targetType == null) {
                 // FIXME: augmentation should be added as last, all types should already be generated\r
                 // and have assigned Java Types,\r
-                val targetModule = findParentModule(schemaContext, targetSchemaNode);\r
-                val targetBasePackage = moduleNamespaceToPackageName(targetModule);\r
-                val typePackage = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());\r
-                val targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();\r
-                val typeName = parseToClassName(targetSchemaNodeName);\r
-                targetType = new ReferencedTypeImpl(typePackage, typeName);\r
-            }\r
-            val augChildNodes = augSchema.childNodes;\r
+                val targetModule = findParentModule(schemaContext, targetSchemaNode);
+                val targetBasePackage = moduleNamespaceToPackageName(targetModule);
+                val typePackage = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());
+                val targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();
+                val typeName = parseToClassName(targetSchemaNodeName);
+                targetType = new ReferencedTypeImpl(typePackage, typeName);
+            }
+            val augChildNodes = augSchema.childNodes;
+
+            if (!(targetSchemaNode instanceof ChoiceNode)) {
+                var packageName = augmentPackageName;
+                if (parentUsesNode != null) {
+                    packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath);
+                }
+                val augTypeBuilder = addRawAugmentGenTypeDefinition(packageName, augmentPackageName, targetType,
+                    augSchema);
+                val augType = augTypeBuilder.toInstance();
+                genTypes.add(augType);
+            } else {
+                genTypes.addAll(
+                    generateTypesFromAugmentedChoiceCases(augmentPackageName, targetType, augChildNodes,
+                        targetSchemaNode as ChoiceNode));
+            }
+            genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes, module));
+        }
+
+        return genTypes;
+    }\r
 \r
-            if(!(targetSchemaNode instanceof ChoiceNode)) {\r
-                var packageName = augmentPackageName;\r
-                if (addedByUses) {\r
-                    packageName = packageNameForGeneratedType(augmentPackageName, augSchema.targetPath);\r
+    /**\r
+     * Utility method which search for original node defined in grouping.\r
+     */\r
+    private def DataSchemaNode findOriginal(DataSchemaNode node) {\r
+        var DataSchemaNode result = findCorrectTargetFromGrouping(node);\r
+        if (result == null) {\r
+            result = findCorrectTargetFromAugment(node);\r
+            if (result != null) {\r
+                if (result.addedByUses) {\r
+                    result = findOriginal(result);\r
                 }\r
-                val augTypeBuilder = addRawAugmentGenTypeDefinition(packageName, augmentPackageName, targetType, augSchema);\r
-                val augType = augTypeBuilder.toInstance();\r
-                genTypes.add(augType);\r
-            } else {\r
-                genTypes.addAll(generateTypesFromAugmentedChoiceCases(augmentPackageName, targetType, augChildNodes, targetSchemaNode as ChoiceNode));\r
             }\r
-            genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes, module));\r
         }\r
-               \r
-        return genTypes;\r
+        return result;\r
     }\r
 \r
-    private def DataSchemaNode findOriginalTargetFromGrouping(SchemaPath targetPath, Module module, DataSchemaNode targetSchemaNode) {\r
-        val path = new ArrayList<QName>(targetPath.getPath());\r
-        path.remove(path.size()-1);\r
-        var DataNodeContainer parent = null;\r
+    private def DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node) {\r
+        if (!node.augmenting) {\r
+            return null;\r
+        }\r
 \r
-        if (path.isEmpty()) {\r
-            parent = module;\r
+        var String currentName = node.QName.localName;\r
+        var tmpPath = new ArrayList<String>();\r
+        var YangNode parent = node;\r
+        var AugmentationSchema augment = null;\r
+        do {\r
+            parent = (parent as DataSchemaNode).parent;\r
+            if (parent instanceof AugmentationTarget) {\r
+                tmpPath.add(currentName);\r
+                augment = findNodeInAugment((parent as AugmentationTarget).availableAugmentations, currentName);\r
+                if (augment == null) {\r
+                    currentName = (parent as DataSchemaNode).QName.localName; \r
+                }\r
+            }\r
+        } while ((parent as DataSchemaNode).augmenting && augment == null);\r
+\r
+        if (augment == null) {\r
+            return null;\r
         } else {\r
-            parent = findNodeInSchemaContext(schemaContext, path) as DataNodeContainer;\r
+            Collections.reverse(tmpPath);\r
+            var Object actualParent = augment;\r
+            var DataSchemaNode result = null;\r
+            for (name : tmpPath) {\r
+                if (actualParent instanceof DataNodeContainer) {\r
+                    result = (actualParent as DataNodeContainer).getDataChildByName(name);\r
+                    actualParent = (actualParent as DataNodeContainer).getDataChildByName(name);\r
+                } else {\r
+                    if (actualParent instanceof ChoiceNode) {\r
+                        result = (actualParent as ChoiceNode).getCaseNodeByName(name);\r
+                        actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name); \r
+                    }\r
+                }\r
+            }\r
+\r
+            if (result.addedByUses) {\r
+                result = findCorrectTargetFromGrouping(result);\r
+            }\r
+\r
+            return result;\r
         }\r
+    }\r
 \r
-        val Set<UsesNode> usesNodes = parent.getUses();\r
-        if (usesNodes == null || usesNodes.isEmpty()) {\r
-            return targetSchemaNode;\r
+    private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, String name) {\r
+        for (augment : augments) {\r
+            if (augment.getDataChildByName(name) != null) {\r
+                return augment;\r
+            }\r
         }\r
-        val Set<SchemaPath> groupingPaths = new HashSet<SchemaPath>();\r
-        for (uses : usesNodes) {\r
-            groupingPaths.add(uses.getGroupingPath());\r
+        return null;\r
+    }\r
+\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);\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 YangNode parent = node.parent; \r
+            do {\r
+                tmpPath.add(currentName);\r
+                val dataNodeParent = parent as DataNodeContainer;\r
+                for (u : dataNodeParent.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(currentName);\r
+                }\r
+                if (result == null) {\r
+                    currentName = (parent as SchemaNode).QName.localName;\r
+                    if (parent instanceof DataSchemaNode) {\r
+                        parent = (parent as DataSchemaNode).parent;\r
+                    } else {\r
+                        parent = (parent as DataNodeContainer).parent;\r
+                    }\r
+                }\r
+            } while (result == null && !(parent instanceof Module));\r
+\r
+            if (result != null) {\r
+                if (tmpPath.size == 1) {\r
+                    return result;\r
+                } else {\r
+                    var DataSchemaNode newParent = result;\r
+                    Collections.reverse(tmpPath);\r
+                    tmpPath.remove(0);\r
+                    for (name : tmpPath) {\r
+                        newParent = (newParent as DataNodeContainer).getDataChildByName(name);\r
+                    }\r
+                    return newParent;\r
+                }\r
+            }\r
+\r
+            return result;\r
         }\r
-        val Set<GroupingDefinition> groupings = new HashSet<GroupingDefinition>();\r
-        for (gp : groupingPaths) {\r
-            groupings.add(findGrouping(schemaContext, module, gp.getPath()));\r
+    }\r
+\r
+    /**\r
+     * Convenient method to find node added by uses statement.\r
+     */\r
+    private def DataSchemaNode findOriginalTargetFromGrouping(String targetSchemaNodeName, UsesNode parentUsesNode) {\r
+        var SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.groupingPath.path);\r
+        if (!(targetGrouping instanceof GroupingDefinition)) {\r
+            throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);\r
         }\r
 \r
-        var DataSchemaNode result = findNodeInGroupings(groupings, targetSchemaNode.getQName().localName);\r
-        return result;\r
-    }\r
+        var grouping = targetGrouping as GroupingDefinition;\r
+        var result = grouping.getDataChildByName(targetSchemaNodeName);\r
+        if (result == null) {\r
+            return null;\r
+        }\r
+        var boolean fromUses = result.addedByUses;\r
 \r
-    private def DataSchemaNode findNodeInGroupings(Set<GroupingDefinition> groupings, String name) {\r
-        for (gr : groupings) {\r
-            var DataSchemaNode node = gr.getDataChildByName(name);\r
-            if (node != null) {\r
-               return node;\r
+        var Iterator<UsesNode> groupingUses = grouping.uses.iterator;\r
+        while (fromUses) {\r
+            if (groupingUses.hasNext()) {\r
+                grouping = findNodeInSchemaContext(schemaContext, groupingUses.next().groupingPath.path) as GroupingDefinition;\r
+                result = grouping.getDataChildByName(targetSchemaNodeName);\r
+                fromUses = result.addedByUses;\r
+            } else {\r
+                throw new NullPointerException("Failed to generate code for augment in " + parentUsesNode);\r
             }\r
         }\r
-        return null;\r
+\r
+        return result;\r
     }\r
 \r
     /**\r
@@ -1021,31 +1159,31 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            and uses of augment\r
      * @return generated type builder for augment\r
      */\r
-    private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(String augmentPackageName, String basePackageName,
-               Type targetTypeRef, AugmentationSchema augSchema) {
-               var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
-               if (augmentBuilders === null) {
-                       augmentBuilders = new HashMap();
-                       genTypeBuilders.put(augmentPackageName, augmentBuilders);
-               }
-               val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
-
-               val augTypeName = if (augIdentifier !== null) {
-                               parseToClassName(augIdentifier)
-                       } else {
-                               augGenTypeName(augmentBuilders, targetTypeRef.name);
-                       }
-
-               val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
-
-               augTypeBuilder.addImplementsType(DATA_OBJECT);
-               augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
-               addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
-
-               augSchemaNodeToMethods(basePackageName, augTypeBuilder, augSchema.childNodes);
-               augmentBuilders.put(augTypeName, augTypeBuilder);
-               return augTypeBuilder;
-       }\r
+    private def GeneratedTypeBuilder addRawAugmentGenTypeDefinition(String augmentPackageName, String basePackageName,\r
+        Type targetTypeRef, AugmentationSchema augSchema) {\r
+        var Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);\r
+        if (augmentBuilders === null) {\r
+            augmentBuilders = new HashMap();\r
+            genTypeBuilders.put(augmentPackageName, augmentBuilders);\r
+        }\r
+        val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);\r
+\r
+        val augTypeName = if (augIdentifier !== null) {\r
+                parseToClassName(augIdentifier)\r
+            } else {\r
+                augGenTypeName(augmentBuilders, targetTypeRef.name);\r
+            }\r
+\r
+        val augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);\r
+\r
+        augTypeBuilder.addImplementsType(DATA_OBJECT);\r
+        augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));\r
+        addImplementedInterfaceFromUses(augSchema, augTypeBuilder);\r
+\r
+        augSchemaNodeToMethods(basePackageName, augTypeBuilder, augSchema.childNodes);\r
+        augmentBuilders.put(augTypeName, augTypeBuilder);\r
+        return augTypeBuilder;\r
+    }\r
 \r
     /**\r
      *\r
@@ -1080,6 +1218,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
         val List<Type> genTypes = new ArrayList();\r
         val List<DataNodeIterator> augSchemaIts = new ArrayList();\r
         for (childNode : augChildNodes) {\r
+            if (!childNode.addedByUses) {\r
+                \r
+            \r
             if(childNode instanceof DataNodeContainer) {\r
                 augSchemaIts.add(new DataNodeIterator(childNode as DataNodeContainer));\r
 \r
@@ -1095,6 +1236,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 }\r
                 genTypes.addAll(choiceToGeneratedType(augBasePackageName, childNode as ChoiceNode, module));\r
             }\r
+            \r
+            \r
+            }\r
         }\r
 \r
         for (it : augSchemaIts) {\r
@@ -1916,14 +2060,16 @@ public class BindingGeneratorImpl implements BindingGenerator {
             } else {\r
                 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);\r
             }\r
-        } else if(schemaNode instanceof LeafListSchemaNode) {\r
-            resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);\r
-        } else if(schemaNode instanceof ContainerSchemaNode) {\r
-            resolveContainerSchemaNode(basePackageName, typeBuilder, schemaNode as ContainerSchemaNode);\r
-        } else if(schemaNode instanceof ChoiceNode) {\r
-            resolveChoiceSchemaNode(basePackageName,typeBuilder,schemaNode as ChoiceNode);\r
-        } else if(schemaNode instanceof ListSchemaNode) {\r
-            resolveListSchemaNode(basePackageName, typeBuilder, schemaNode as ListSchemaNode);\r
+        } else if (!schemaNode.addedByUses) {\r
+            if (schemaNode instanceof LeafListSchemaNode) {\r
+                resolveLeafListSchemaNode(typeBuilder, schemaNode as LeafListSchemaNode);\r
+            } else if(schemaNode instanceof ContainerSchemaNode) {\r
+                resolveContainerSchemaNode(basePackageName, typeBuilder, schemaNode as ContainerSchemaNode);\r
+            } else if(schemaNode instanceof ChoiceNode) {\r
+                resolveChoiceSchemaNode(basePackageName,typeBuilder,schemaNode as ChoiceNode);\r
+            } else if(schemaNode instanceof ListSchemaNode) {\r
+                resolveListSchemaNode(basePackageName, typeBuilder, schemaNode as ListSchemaNode);\r
+            }\r
         }\r
     }\r
 \r