Fixed bug in generation of return type for list key properties.
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingGeneratorImpl.xtend
index 88fb52d4639c34e34bbba7305b6a6b11fca0a085..e5aa5c4c2286f9660fcfa58319cce5060f79e66c 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,23 +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\r
-\r
+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 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
@@ -95,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;
@@ -184,10 +189,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         val List<Type> filteredGenTypes = new ArrayList();
         for (Module m : modules) {
-            filteredGenTypes.addAll(genCtx.get(m).generatedTypes);
-
-        }
-        //genCtx.clear;
+            filteredGenTypes.addAll(genCtx.get(m).generatedTypes);\r
+            val Set<Type> additionalTypes = (typeProvider as TypeProviderImpl).additionalTypes.get(m)\r
+            if (additionalTypes != null) {\r
+                filteredGenTypes.addAll(additionalTypes)\r
+            }
+        }\r
 
         return filteredGenTypes;
     }
@@ -237,7 +244,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 }
             }
         }
-    }
+    }\r
 \r
     private def GeneratedTypeBuilder processDataSchemaNode(Module module, String basePackageName,
         GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, DataSchemaNode node) {
@@ -425,7 +432,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         interfaceBuilder.addImplementsType(Types.typeForClass(RpcService));
         for (rpc : rpcDefinitions) {
             if (rpc !== null) {
-                val rpcName = parseToClassName(rpc.QName.localName);
+                val rpcName = BindingMapping.getClassName(rpc.QName);
                 val rpcMethodName = parseToValidParamName(rpcName);
                 val method = interfaceBuilder.addMethod(rpcMethodName);
                 val input = rpc.input;
@@ -561,7 +568,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             return;
         }
         val packageName = packageNameForGeneratedType(basePackageName, identity.path);
-        val genTypeName = parseToClassName(identity.QName.localName);
+        val genTypeName = BindingMapping.getClassName(identity.QName);
         val newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
         val baseIdentity = identity.baseIdentity;
         if (baseIdentity === null) {
@@ -569,22 +576,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
         } else {
             val baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
             val returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
-            val returnTypeName = parseToClassName(baseIdentity.QName.localName);
+            val returnTypeName = BindingMapping.getClassName(baseIdentity.QName);
             val gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
             newType.setExtendsType(gto);
         }
         newType.setAbstract(true);\r
         val qname = identity.QName;\r
-        newType.addConstant(QName.typeForClass,"QNAME",'''\r
-            org.opendaylight.yangtools.yang.common.QName.create("«qname.namespace»","«qname.formattedRevision»","«qname.localName»")\r
-        ''');
+        \r
+        newType.qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,qname);\r
+        
         genCtx.get(module).addIdentityType(identity.QName,newType)
+    }\r
+    \r
+    private static def qnameConstant(GeneratedTypeBuilderBase<?> toBuilder, String constantName, QName name) {
+        toBuilder.addConstant(QName.typeForClass,constantName,'''\r
+            org.opendaylight.yangtools.yang.common.QName.create("«name.namespace»","«name.formattedRevision»","«name.localName»")\r
+        ''');
     }
 
     /**\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
@@ -627,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
@@ -660,14 +673,14 @@ 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, String enumName,
+    private def EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, QName enumName,
         GeneratedTypeBuilder typeBuilder) {
         if ((enumTypeDef !== null) && (typeBuilder !== null) && (enumTypeDef.QName !== null) &&
             (enumTypeDef.QName.localName !== null)) {
-            val enumerationName = parseToClassName(enumName);
+            val enumerationName = BindingMapping.getClassName(enumName);
             val enumBuilder = typeBuilder.addEnumeration(enumerationName);
             enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
             return enumBuilder;
@@ -692,7 +705,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private def GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
         checkArgument(module !== null, "Module reference cannot be NULL.");
         val packageName = moduleNamespaceToPackageName(module);
-        val moduleName = parseToClassName(module.name) + postfix;
+        val moduleName = BindingMapping.getClassName(module.name) + postfix;
         return new GeneratedTypeBuilderImpl(packageName, moduleName);
     }
 
@@ -707,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
@@ -725,12 +738,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
         checkState(augSchema.targetPath !== null,
             "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
+        processUsesAugments(augSchema, module);\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);
@@ -742,7 +752,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     "Failed to find target node from grouping for augmentation " + augSchema + " in module " +
                         module.name);
             }
-        }
+        }\r
+\r
+        if (targetSchemaNode == null) {\r
+            throw new IllegalArgumentException("augment target not found: " + targetPath)\r
+        }\r
 
         if (targetSchemaNode !== null) {
             var targetTypeBuilder = findChildNodeByPath(targetSchemaNode.path)
@@ -786,20 +800,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 QName currentName = node.QName\r
+        var Object currentNode = node
+        var Object parent = node;\r
+        val tmpPath = new ArrayList<QName>()\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\r
+                    currentNode = parent
                 }
             }
         } while ((parent as DataSchemaNode).augmenting && augment == null);
@@ -807,107 +831,172 @@ 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) {
                 if (actualParent instanceof DataNodeContainer) {
-                    result = (actualParent as DataNodeContainer).getDataChildByName(name);
-                    actualParent = (actualParent as DataNodeContainer).getDataChildByName(name);
+                    result = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
+                    actualParent = (actualParent as DataNodeContainer).getDataChildByName(name.localName);
                 } else {
                     if (actualParent instanceof ChoiceNode) {
-                        result = (actualParent as ChoiceNode).getCaseNodeByName(name);
-                        actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name);
+                        result = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
+                        actualParent = (actualParent as ChoiceNode).getCaseNodeByName(name.localName);
                     }
                 }
             }
 
-            if (result.addedByUses) {
-                result = findCorrectTargetFromGrouping(result);
+            if (result.addedByUses) {\r
+                result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree);
             }
 
             return result;
         }
     }
 
-    private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, String name) {
-        for (augment : augments) {
-            if (augment.getDataChildByName(name) != null) {
+    private def AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
+        for (augment : augments) {\r
+            val DataSchemaNode node = augment.getDataChildByName(name);\r
+            if (node != null) {
                 return augment;
             }
         }
         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);
+            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 QName currentName = node.QName\r
+            var tmpPath = new ArrayList<QName>()\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
+                        result = getResultFromUses(u, currentName.localName)\r
+                    }\r
+                }\r
+                if (result == null) {
+                    currentName = (parent as SchemaNode).QName
+                    if (parent instanceof SchemaNode) {
+                        val SchemaPath nodeSp = (parent as SchemaNode).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 {
+                        throw new IllegalArgumentException("Failed to generate code for augment")
+                    }
+                }\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 QName currentName = node.QName
+        var tmpPath = new ArrayList<QName>()\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)
+            }\r
+
+            val dataNodeParent = parent as DataNodeContainer;
+            for (u : dataNodeParent.uses) {
+                if (result == null) {\r
+                    result = getResultFromUses(u, currentName.localName)
                 }
-                var gr = targetGrouping as GroupingDefinition;
-                result = gr.getDataChildByName(node.QName.localName);
             }
             if (result == null) {
-                throw new IllegalArgumentException("Failed to generate code for augment");
+                i = i + 1\r
+                currentName = (parent as SchemaNode).QName
+            }
+        } 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<QName> tmpPath, DataSchemaNode node) {
+        var DataSchemaNode result = node
+        if (tmpPath.size == 1) {
+            if (result != null && result.addedByUses) {
+                result = findOriginal(result);
             }
             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) {
-                    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
-                    }
-                }
-                if (result == null) {
-                    currentName = (parent as SchemaNode).QName.localName;
-                    if (parent instanceof DataSchemaNode) {
-                        parent = (parent as DataSchemaNode).parent;
-                    } else {
-                        parent = (parent as DataNodeContainer).parent;
-                    }
-                }
-            } while (result == null && !(parent instanceof Module));
+            var DataSchemaNode newParent = result;
+            Collections.reverse(tmpPath);
 
-            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;
-                }
+            tmpPath.remove(0);
+            for (name : tmpPath) {\r
+                // searching by local name is must, because node has different namespace in its original location
+                newParent = (newParent as DataNodeContainer).getDataChildByName(name.localName);
             }
-
-            return result;
+            if (newParent != null && newParent.addedByUses) {
+                newParent = findOriginal(newParent);
+            }
+            return newParent;
         }
-    }
+    }\r
+
 
     /**\r
      * Convenient method to find node added by uses statement.\r
@@ -969,7 +1058,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         val augIdentifier = getAugmentIdentifier(augSchema.unknownSchemaNodes);
 
         val augTypeName = if (augIdentifier !== null) {
-                parseToClassName(augIdentifier)
+                BindingMapping.getClassName(augIdentifier)
             } else {
                 augGenTypeName(augmentBuilders, targetTypeRef.name);
             }
@@ -1149,12 +1238,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
         checkArgument(basePackageName !== null, "Base Package Name cannot be NULL.");
         checkArgument(choiceNode !== null, "Choice Schema Node cannot be NULL.");
 
-        val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
-        val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
-        constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
-        choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
-        genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
-        generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
+        if (!choiceNode.addedByUses) {
+            val packageName = packageNameForGeneratedType(basePackageName, choiceNode.path);
+            val choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
+            constructGetter(parent, choiceNode.QName.localName, choiceNode.description, choiceTypeBuilder);
+            choiceTypeBuilder.addImplementsType(DataContainer.typeForClass);
+            genCtx.get(module).addChildNodeType(choiceNode.path, choiceTypeBuilder)
+            generateTypesFromChoiceCases(module, basePackageName, parent, choiceTypeBuilder.toInstance, choiceNode);
+        }
     }
 
     /**\r
@@ -1202,7 +1293,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;
@@ -1219,7 +1317,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)
@@ -1267,7 +1370,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
@@ -1333,27 +1443,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 val TypeDefinition<?> typeDef = leaf.type;
 
                 var Type returnType = null;
+                var GeneratedTOBuilder genTOBuilder;
                 if (typeDef instanceof EnumTypeDefinition) {
                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
                     val enumTypeDef = typeDef as EnumTypeDefinition;
-                    val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName, typeBuilder);
+                    val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.QName, typeBuilder);
 
                     if (enumBuilder !== null) {
                         returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);
                     }
                     (typeProvider as TypeProviderImpl).putReferencedType(leaf.path, returnType);
                 } else if (typeDef instanceof UnionType) {
-                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
-                    if (genTOBuilder !== null) {
-                        returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);\r
+                    if (genTOBuilder !== null) {\r
+                        returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule)\r
                     }
                 } else if (typeDef instanceof BitsTypeDefinition) {
-                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, leaf, parentModule);
-                    if (genTOBuilder !== null) {
-                        returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);\r
+                    if (genTOBuilder !== null) {\r
+                        returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
                     }
-                } else {\r
-                    val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);\r
+                } else {
+                    val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
                 }
                 if (returnType !== null) {
@@ -1398,7 +1509,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 val Class<RoutingContext> clazz = typeof(RoutingContext);
                 val AnnotationTypeBuilder rc = getter.addAnnotation(clazz.package.name, clazz.simpleName);
                 val packageName = packageNameForGeneratedType(basePackageName, identity.path);
-                val genTypeName = parseToClassName(identity.QName.localName);
+                val genTypeName = BindingMapping.getClassName(identity.QName.localName);
                 rc.addParameter("value", packageName + "." + genTypeName + ".class");
             }
         }
@@ -1442,7 +1553,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         </ul>\r
      */
     private def boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
-        boolean isReadOnly) {
+        boolean isReadOnly, Module module) {
         if ((leaf !== null) && (toBuilder !== null)) {
             val leafName = leaf.QName.localName;
             var String leafDesc = leaf.description;
@@ -1450,11 +1561,24 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 leafDesc = "";
             }
 
-            if (leafName !== null) {
-                val TypeDefinition<?> typeDef = leaf.type;
+            if (leafName !== null) {\r
+                var Type returnType = null;
+                val TypeDefinition<?> typeDef = leaf.type;\r
+                if (typeDef instanceof UnionTypeDefinition) {\r
+                    // GeneratedType for this type definition should be already created\r
+                    var qname = typeDef.QName\r
+                    var Module unionModule = null\r
+                    if (qname.prefix == null || qname.prefix.empty) {\r
+                        unionModule = module\r
+                    } else {\r
+                        unionModule = findModuleFromImports(module.imports, qname.prefix)\r
+                    }\r
+                    val ModuleContext mc = genCtx.get(unionModule)\r
+                    returnType = mc.typedefs.get(typeDef.path)\r
+                } else {\r
+                    returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);\r
+                }
 
-                // TODO: properly resolve enum types\r
-                val returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
                 if (returnType !== null) {
                     val propBuilder = toBuilder.addProperty(parseToValidParamName(leafName));
                     propBuilder.setReadOnly(isReadOnly);
@@ -1489,7 +1613,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      */
     private def boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
         if ((node !== null) && (typeBuilder !== null)) {
-            val nodeName = node.QName.localName;
+            val nodeName = node.QName;
             var String nodeDesc = node.description;
             if (nodeDesc === null) {
                 nodeDesc = "";
@@ -1506,10 +1630,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);\r
                     (typeProvider as TypeProviderImpl).putReferencedType(node.path, returnType);\r
                 } else if (typeDef instanceof UnionType) {\r
-                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
-                    returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
+                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);\r
+                    if (genTOBuilder !== null) {\r
+                        returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule)\r
+                    }
                 } else if (typeDef instanceof BitsTypeDefinition) {\r
-                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
+                    val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);\r
                     returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
                 } else {\r
                     val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);\r
@@ -1517,12 +1643,39 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 }\r
 
                 val listType = Types.listTypeFor(returnType);
-                constructGetter(typeBuilder, nodeName, nodeDesc, listType);
+                constructGetter(typeBuilder, nodeName.localName, nodeDesc, listType);
                 return true;
             }
         }
         return false;
     }
+\r
+    private def Type createReturnTypeForUnion(GeneratedTOBuilder genTOBuilder, TypeDefinition<?> typeDef,
+        GeneratedTypeBuilder typeBuilder, Module parentModule) {
+        val Type returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);
+        genTOBuilder.setTypedef(true);
+        genTOBuilder.setIsUnion(true);
+        (typeProvider as TypeProviderImpl).addUnitsToGenTO(genTOBuilder, typeDef.getUnits());
+
+        // union builder\r
+        val GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(typeBuilder.getPackageName(),
+            genTOBuilder.getName() + "Builder");
+        unionBuilder.setIsUnionBuilder(true);
+        val MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
+        method.setReturnType(returnType);
+        method.addParameter(Types.STRING, "defaultValue");
+        method.setAccessModifier(AccessModifier.PUBLIC);
+        method.setStatic(true);
+
+        val Set<Type> types = (typeProvider as TypeProviderImpl).additionalTypes.get(parentModule);
+        if (types == null) {
+            (typeProvider as TypeProviderImpl).additionalTypes.put(parentModule,
+                Sets.newHashSet(unionBuilder.toInstance))
+        } else {
+            types.add(unionBuilder.toInstance)
+        }
+        return returnType
+    }\r
 
     private def GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
         return addDefaultInterfaceDefinition(packageName, schemaNode, null);
@@ -1553,10 +1706,7 @@ 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;
-        addConstant(QName.typeForClass,"QNAME",'''\r
-            org.opendaylight.yangtools.yang.common.QName.create("«qname.namespace»","«qname.formattedRevision»","«qname.localName»")\r
-        ''');\r
+        qnameConstant(BindingMapping.QNAME_STATIC_FIELD_NAME,schemaNode.QName);\r
         if (parent === null) {
             addImplementsType(DATA_OBJECT);
         } else {
@@ -1607,7 +1757,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
      */
@@ -1621,9 +1771,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         var String genTypeName;
         if (prefix === null) {
-            genTypeName = parseToClassName(schemaNodeName);
+            genTypeName = BindingMapping.getClassName(schemaNodeName);
         } else {
-            genTypeName = prefix + parseToClassName(schemaNodeName);
+            genTypeName = prefix + BindingMapping.getClassName(schemaNodeName);
         }
 
         //FIXME: Validation of name conflict\r
@@ -1657,7 +1807,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         } else {
             method.append("get");
         }
-        method.append(parseToClassName(localName));
+        method.append(BindingMapping.getPropertyName(localName).toFirstUpper);
         return method.toString();
     }
 
@@ -1723,7 +1873,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             val leafName = leaf.QName.localName;\r
             resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
             if (listKeys.contains(leafName)) {
-                resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
+                resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true, module)
             }
         } else if (!schemaNode.addedByUses) {
             if (schemaNode instanceof LeafListSchemaNode) {
@@ -1786,7 +1936,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         var GeneratedTOBuilder genTOBuilder = null;
         if ((list.keyDefinition !== null) && (!list.keyDefinition.isEmpty())) {
             val listName = list.QName.localName + "Key";
-            val String genTOName = parseToClassName(listName);
+            val String genTOName = BindingMapping.getClassName(listName);
             genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
         }
         return genTOBuilder;
@@ -1816,15 +1966,31 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return generated TO builder for <code>typeDef</code>\r
      */
     private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
-        String leafName, DataSchemaNode leaf, Module parentModule) {
-        val classNameFromLeaf = parseToClassName(leafName);
+        DataSchemaNode leaf, Module parentModule) {
+        val classNameFromLeaf = BindingMapping.getClassName(leaf.QName);
         val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
         val packageName = typeBuilder.fullyQualifiedName;
-        if (typeDef instanceof UnionTypeDefinition) {
-            genTOBuilders.addAll(
-                (typeProvider as TypeProviderImpl).
-                    provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),
-                        classNameFromLeaf, leaf));
+        if (typeDef instanceof UnionTypeDefinition) {\r
+            val List<GeneratedTOBuilder> types = (typeProvider as TypeProviderImpl).\r
+                    provideGeneratedTOBuildersForUnionTypeDef(packageName, (typeDef as UnionTypeDefinition),\r
+                        classNameFromLeaf, leaf); 
+            genTOBuilders.addAll(types);\r
+                        \r
+            \r
+        var GeneratedTOBuilder resultTOBuilder = null;\r
+        if (!types.isEmpty()) {\r
+            resultTOBuilder = types.remove(0);\r
+            for (GeneratedTOBuilder genTOBuilder : types) {\r
+                resultTOBuilder.addEnclosingTransferObject(genTOBuilder);\r
+            }\r
+        }\r
+\r
+        val GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");\r
+        genPropBuilder.setReturnType(Types.primitiveType("char[]", null));\r
+        resultTOBuilder.addEqualsIdentity(genPropBuilder);\r
+        resultTOBuilder.addHashIdentity(genPropBuilder);\r
+        resultTOBuilder.addToStringProperty(genPropBuilder);\r
+
         } else if (typeDef instanceof BitsTypeDefinition) {
             genTOBuilders.add(
                 ((typeProvider as TypeProviderImpl) ).
@@ -1844,7 +2010,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
@@ -1900,8 +2066,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
 }