Binding generator v2 - uses statement - support choice
[mdsal.git] / binding2 / mdsal-binding2-generator-impl / src / main / java / org / opendaylight / mdsal / binding / javav2 / generator / impl / GenHelperUtil.java
index 66f31373e0ca3866b66804deea2110322f28ef4d..64b547bc4699e334f0d60f21664ac240758bf5fd 100644 (file)
@@ -20,11 +20,13 @@ import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenU
 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant;
 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
+import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTypeBuilder;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.computeDefaultSUID;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION;
 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
+import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.wildcardTypeFor;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
@@ -66,6 +68,7 @@ import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
@@ -198,6 +201,16 @@ final class GenHelperUtil {
         return null;
      }
 
+    static GeneratedTOBuilder findIdentityByQname(final QName qname, final Map<Module, ModuleContext> genCtx) {
+        for (final ModuleContext ctx : genCtx.values()) {
+            final GeneratedTOBuilder result = ctx.getIdentities().get(qname);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
     /**
      * Adds the methods to <code>typeBuilder</code> which represent subnodes of
      * node for which <code>typeBuilder</code> was created.
@@ -271,6 +284,75 @@ final class GenHelperUtil {
         return genCtx;
     }
 
+    static void addUsesImplements(final SchemaNode superNode, final Module superModule,
+            final SchemaNode node, final Module module,
+            final SchemaContext schemaContext, Map<Module, ModuleContext> genCtx, final BindingNamespaceType namespaceType ) {
+
+        if (superNode instanceof DataNodeContainer) {
+            for (DataSchemaNode superChildNode : ((DataNodeContainer)superNode).getChildNodes()) {
+                if (superChildNode instanceof DataNodeContainer || superChildNode instanceof ChoiceSchemaNode) {
+                    final QName childQName = QName.create(node.getQName(), superChildNode.getQName().getLocalName());
+                    DataSchemaNode childNode = ((DataNodeContainer)node).getDataChildByName(childQName);
+                    Preconditions.checkNotNull(childNode, node.getPath() + "->" + childQName.toString());
+
+                    final GeneratedTypeBuilder type = genCtx.get(module).getChildNode(childNode.getPath());
+                    final GeneratedTypeBuilder superType = genCtx.get(superModule).getChildNode(superChildNode.getPath());
+
+                    //TODO:delete this after supporting uses augment
+                    if (type == null || superType == null) {
+                        return;
+                    }
+                    Preconditions.checkNotNull(type, module.toString() + "->" + childNode.getPath().toString());
+                    Preconditions.checkNotNull(superType, superModule.toString() + "->" + superChildNode.getPath().toString());
+                    type.addImplementsType(superType);
+                    if (superChildNode instanceof ListSchemaNode
+                            && !((ListSchemaNode) superChildNode).getKeyDefinition().isEmpty()) {
+                        if (namespaceType.equals(BindingNamespaceType.Grouping)) {
+                            genCtx.get(module).getKeyType(childNode.getPath())
+                                    .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
+                        } else if (namespaceType.equals(BindingNamespaceType.Data)) {
+                            genCtx.get(module).getKeyGenTO(childNode.getPath())
+                                    .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
+                        }
+                    }
+                    addUsesImplements(superChildNode, superModule, childNode, module, schemaContext, genCtx, namespaceType);
+                }
+            }
+        } else if (superNode instanceof ChoiceSchemaNode) {
+            for (ChoiceCaseNode superCaseNode : ((ChoiceSchemaNode)superNode).getCases()) {
+                final QName childQName = QName.create(node.getQName(), superCaseNode.getQName().getLocalName());
+                ChoiceCaseNode caseNode = ((ChoiceSchemaNode)node).getCaseNodeByName(childQName);
+                Preconditions.checkNotNull(caseNode, node.getPath() + "->" + childQName.toString());
+
+                final GeneratedTypeBuilder type = genCtx.get(module).getCase(caseNode.getPath());
+                final GeneratedTypeBuilder superType = genCtx.get(superModule).getCase(superCaseNode.getPath());
+                Preconditions.checkNotNull(type, module.toString() + "->" + caseNode.getPath().toString());
+                Preconditions.checkNotNull(superType, superModule.toString() + "->" + superCaseNode.getPath().toString());
+                type.addImplementsType(superType);
+                addUsesImplements(superCaseNode, superModule, caseNode, module, schemaContext, genCtx, namespaceType);
+            }
+        } else {
+            throw new IllegalArgumentException("Not support node :" + node.getPath().toString());
+        }
+    }
+
+    static Map<Module, ModuleContext> processUsesImplements(final SchemaNode node, final Module module,
+            final SchemaContext schemaContext, Map<Module, ModuleContext> genCtx, final BindingNamespaceType namespaceType) {
+        if (node instanceof DataNodeContainer) {
+            for (final UsesNode usesNode : ((DataNodeContainer)node).getUses()) {
+                final SchemaNode groupingNode = SchemaContextUtil.findDataSchemaNode(schemaContext, usesNode.getGroupingPath());
+                Preconditions.checkNotNull(groupingNode, module.toString() + "->"
+                        + usesNode.getGroupingPath().toString());
+                Preconditions.checkState(groupingNode instanceof GroupingDefinition,
+                        module.toString() + "->" + usesNode.getGroupingPath().toString());
+                final Module superModule = SchemaContextUtil.findParentModule(schemaContext, groupingNode);
+                GroupingDefinition grouping = (GroupingDefinition) groupingNode;
+                addUsesImplements(grouping, superModule, node, module, schemaContext, genCtx, namespaceType);
+            }
+        }
+        return genCtx;
+    }
+
     static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
         for (final ModuleContext ctx : genCtx.values()) {
             final GeneratedTypeBuilder result = ctx.getChildNode(path);
@@ -291,6 +373,16 @@ final class GenHelperUtil {
         return null;
     }
 
+    static GeneratedTypeBuilder findKeyByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
+        for (final ModuleContext ctx : genCtx.values()) {
+            final GeneratedTypeBuilder result = ctx.getKeyType(path);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
     static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
             final Type targetTypeRef, final List<AugmentationSchema> schemaPathAugmentListEntry,
             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
@@ -612,17 +704,17 @@ final class GenHelperUtil {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
 
-        if (!choiceNode.isAddedByUses()) {
-            final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(basePackageName, choiceNode,
-                    schemaContext, "", "", verboseClasssComments, genTypeBuilders, namespaceType);
-            constructGetter(parent, choiceNode.getQName().getLocalName(),
-                    choiceNode.getDescription(), choiceTypeBuilder, choiceNode.getStatus());
+        final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(basePackageName, choiceNode,
+                schemaContext, "", "", verboseClasssComments, genTypeBuilders, namespaceType);
+        constructGetter(parent, choiceNode.getQName().getLocalName(),
+                choiceNode.getDescription(), choiceTypeBuilder, choiceNode.getStatus());
+        if (namespaceType.equals(BindingNamespaceType.Data)) {
             choiceTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, choiceTypeBuilder));
-            annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
-            genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
-            generateTypesFromChoiceCases(module, schemaContext, genCtx, basePackageName, choiceTypeBuilder.toInstance(),
-                choiceNode, verboseClasssComments, typeProvider, genTypeBuilders, namespaceType);
         }
+        annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
+        genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
+        generateTypesFromChoiceCases(module, schemaContext, genCtx, basePackageName, choiceTypeBuilder.toInstance(),
+            choiceNode, verboseClasssComments, typeProvider, genTypeBuilders, namespaceType);
     }
 
     private static void containerToGenType(final Module module, final String basePackageName,
@@ -644,6 +736,7 @@ final class GenHelperUtil {
             }
             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
                     schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
+            processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
         }
     }
 
@@ -657,38 +750,64 @@ final class GenHelperUtil {
                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
         if (genType != null) {
             final String nodeName = node.getQName().getLocalName();
-            constructGetter(parent, nodeName, node.getDescription(), Types.listTypeFor(genType), node.getStatus());
+
+            Type getterReturnType = Types.listTypeFor(genType);
+            if (namespaceType.equals(BindingNamespaceType.Grouping)) {
+                getterReturnType = Types.listTypeFor(wildcardTypeFor(genType.getPackageName(), genType.getName(),
+                                true, true));
+            }
+            constructGetter(parent, nodeName, node.getDescription(), getterReturnType, node.getStatus());
+
             final List<QName> listKeys = node.getKeyDefinition();
             final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
                     BindingNamespaceType.Key)).append('.').append(nodeName).toString();
+            //FIXME: Is it neccessary to generate interface of key and implemented by class?
+            if (namespaceType.equals(BindingNamespaceType.Grouping)) {
+                final GeneratedTypeBuilder genTypeBuilder = resolveListKeyTypeBuilder(packageName, node);
+                for (final DataSchemaNode schemaNode : node.getChildNodes()) {
+                    if (!schemaNode.isAugmenting()) {
+                        addSchemaNodeToListTypeBuilders(nodeName, basePackageName, schemaNode, genType, genTypeBuilder, listKeys,
+                                module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments, namespaceType);
+                    }
+                }
+                if (genTypeBuilder != null) {
+                    typeBuildersToGenTypes(module, genType, genTypeBuilder.toInstance(), genCtx, namespaceType);
+                    genCtx.get(module).addKeyType(node.getPath(), genTypeBuilder);
+                }
+            } else {
+                final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
+                for (final DataSchemaNode schemaNode : node.getChildNodes()) {
+                    if (!schemaNode.isAugmenting()) {
+                        addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
+                                module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments, namespaceType);
+                    }
+                }
 
-            final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
+                // serialVersionUID
+                if (genTOBuilder != null) {
+                    final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
+                    prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
+                    genTOBuilder.setSUID(prop);
 
-            for (final DataSchemaNode schemaNode : node.getChildNodes()) {
-                if (!schemaNode.isAugmenting()) {
-                    addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
-                            module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments, namespaceType);
+                    typeBuildersToGenTypes(module, genType, genTOBuilder.toInstance(), genCtx, namespaceType);
+                    genCtx.get(module).addGeneratedTOBuilder(node.getPath(), genTOBuilder);
                 }
             }
-
-            // serialVersionUID
-            if (genTOBuilder != null) {
-                final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
-                prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
-                genTOBuilder.setSUID(prop);
-            }
-
-            typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx);
         }
     }
 
     private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
-            final GeneratedTOBuilder genTOBuilder, final Map<Module, ModuleContext> genCtx) {
+            final Type keyType, final Map<Module, ModuleContext> genCtx,
+            final BindingNamespaceType namespaceType) {
         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
-        if (genTOBuilder != null) {
-            final GeneratedTransferObject genTO = genTOBuilder.toInstance();
-            constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT);
-            genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
+        if (keyType != null) {
+            Type returnKeyType = keyType;
+            if (namespaceType.equals(BindingNamespaceType.Grouping)) {
+                returnKeyType = wildcardTypeFor(keyType.getPackageName(), keyType.getName(),
+                        true, true);
+            }
+            constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", returnKeyType, Status.CURRENT);
+
         }
     }
 
@@ -814,7 +933,7 @@ final class GenHelperUtil {
     private static boolean resolveLeafListSchemaNode(final SchemaContext schemaContext, final GeneratedTypeBuilder
             typeBuilder, final LeafListSchemaNode node, final Module module, final TypeProvider typeProvider,
             final Map<Module, ModuleContext> genCtx) {
-        if (node == null || typeBuilder == null || node.isAddedByUses()) {
+        if (node == null || typeBuilder == null) {
             return false;
         }
 
@@ -902,7 +1021,7 @@ final class GenHelperUtil {
         }
 
         for (final ChoiceCaseNode caseNode : caseNodes) {
-            if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
+            if (caseNode != null && !caseNode.isAugmenting()) {
                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(basePackageName, caseNode,
                     module, genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
                 caseTypeBuilder.addImplementsType(refChoiceType);
@@ -1028,13 +1147,48 @@ final class GenHelperUtil {
                     typeProvider);
             if (listKeys.contains(leafQName)) {
                 if (type == null) {
-                    resolveLeafSchemaNodeAsProperty(schemaContext, typeProvider, genCtx, genTOBuilder, leaf, true,
+                    resolveLeafSchemaNodeAsProperty(nodeName, schemaContext, typeProvider, genCtx, genTOBuilder, leaf, true,
                         module);
                 } else {
-                    AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, type, true);
+                    AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, genTOBuilder, leaf, type, true);
                 }
             }
-        } else if (!schemaNode.isAddedByUses()) {
+        } else {
+            if (schemaNode instanceof LeafListSchemaNode) {
+                resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
+                        typeProvider, genCtx);
+            } else if (schemaNode instanceof ContainerSchemaNode) {
+                containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
+                        schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
+            } else if (schemaNode instanceof ListSchemaNode) {
+                listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
+                        schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
+            } else if (schemaNode instanceof ChoiceSchemaNode) {
+                choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder,
+                        (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType);
+            }
+        }
+    }
+
+    private static void addSchemaNodeToListTypeBuilders(final String nodeName, final String basePackageName,
+                                                    final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder,
+                                                    final GeneratedTypeBuilder genTypeBuilder, final List<QName> listKeys, final Module module,
+                                                    final TypeProvider typeProvider, final SchemaContext schemaContext, final Map<Module, ModuleContext> genCtx,
+                                                    final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments,
+                                                    final BindingNamespaceType namespaceType) {
+        checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
+        checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
+
+        if (schemaNode instanceof LeafSchemaNode) {
+            final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
+            final QName leafQName = leaf.getQName();
+            final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module,
+                    typeProvider);
+            if (listKeys.contains(leafQName)) {
+                resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, genTypeBuilder, genCtx, leaf, module,
+                        typeProvider);
+            }
+        } else {
             if (schemaNode instanceof LeafListSchemaNode) {
                 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
                         typeProvider, genCtx);
@@ -1051,7 +1205,7 @@ final class GenHelperUtil {
         }
     }
 
-    private static boolean resolveLeafSchemaNodeAsProperty(final SchemaContext schemaContext, final TypeProvider
+    private static boolean resolveLeafSchemaNodeAsProperty(final String nodeName, final SchemaContext schemaContext, final TypeProvider
             typeProvider, final Map<Module, ModuleContext> genCtx, final GeneratedTOBuilder
             toBuilder, final LeafSchemaNode leaf, final boolean isReadOnly, final Module module) {
 
@@ -1076,7 +1230,7 @@ final class GenHelperUtil {
             } else {
                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
             }
-            return AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(toBuilder, leaf, returnType, isReadOnly);
+            return AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, toBuilder, leaf, returnType, isReadOnly);
         }
         return false;
     }
@@ -1108,8 +1262,6 @@ final class GenHelperUtil {
         genType.setParentTypeForBuilder(childOf);
         if (node instanceof DataNodeContainer) {
             genCtx.get(module).addChildNodeType(node, genType);
-            genCtx = groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings(), genCtx, schemaContext,
-                    verboseClassComments, genTypeBuilders, typeProvider);
             processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
                     verboseClassComments, typeProvider, namespaceType);
         }
@@ -1186,10 +1338,9 @@ final class GenHelperUtil {
         genCtx.get(module).addGroupingType(grouping, genType);
         resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
                 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping);
-        genCtx = groupingsToGenTypes(module, grouping.getGroupings(), genCtx, schemaContext, verboseClassComments,
-                genTypeBuilders, typeProvider);
         genCtx = processUsesAugments(schemaContext, grouping, module, genCtx, genTypeBuilders, verboseClassComments,
                 typeProvider, BindingNamespaceType.Grouping);
+        genCtx = processUsesImplements(grouping, module, schemaContext, genCtx, BindingNamespaceType.Grouping);
         return genCtx;
     }
 
@@ -1216,60 +1367,55 @@ final class GenHelperUtil {
      */
     static Map<Module, ModuleContext> identityToGenType(final Module module, final String basePackageName,
             final IdentitySchemaNode identity, final SchemaContext schemaContext, Map<Module, ModuleContext> genCtx,
-            boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
-            final TypeProvider typeProvider, Map<QName, GeneratedTOBuilderImpl> generatedIdentities) {
+            boolean verboseClassComments) {
 
-        //check first if identity has been resolved as base identity of some other one
-        GeneratedTOBuilderImpl newType = generatedIdentities.get(identity.getQName());
+        resolveIdentitySchemaNode(basePackageName, schemaContext, identity, module, verboseClassComments, genCtx);
+        return genCtx;
+    }
+
+    private static GeneratedTOBuilder resolveIdentitySchemaNode(final String basePackageName, final SchemaContext schemaContext,
+            final IdentitySchemaNode identity, final Module module, final boolean verboseClassComments,
+            final Map<Module, ModuleContext> genCtx) {
+        Preconditions.checkNotNull(identity,"Identity can not be null!");
 
+        //check first if identity has been resolved as base identity of some other one
+        GeneratedTOBuilder newType = findIdentityByQname(identity.getQName(), genCtx);
         if (newType == null) {
+            final Module parentModule = SchemaContextUtil.findParentModule(schemaContext, identity);
+            Preconditions.checkState(module.equals(parentModule),
+                    "If the type is null ,it must be in the same module, otherwise it must has been"
+                            + "resolved by an imported module.");
+
             final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity.getPath(),
                     BindingNamespaceType.Identity);
             newType = new GeneratedTOBuilderImpl(packageName, identity.getQName().getLocalName(), true, false);
-        }
 
-        final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
-        if (baseIdentities.size() == 0) {
-            //no base - abstract
-            final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
-                BaseIdentity.class.getSimpleName());
-            newType.setExtendsType(gto.toInstance());
-            generatedIdentities.put(identity.getQName(), newType);
-        } else {
-            //one base - inheritance
-            final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next();
-            final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(schemaContext, baseIdentity);
-            final String returnTypePkgName = new StringBuilder(BindingMapping.getRootPackageName
-                    (baseIdentityParentModule))
-                    .append('.')
-                    .append(BindingNamespaceType.Identity.getPackagePrefix())
-                    .toString();
-
-            final GeneratedTOBuilderImpl existingIdentityGto = generatedIdentities.get(baseIdentity.getQName());
-            if (existingIdentityGto != null) {
-                newType.setExtendsType(existingIdentityGto.toInstance());
-            } else {
-                final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(returnTypePkgName,
-                        baseIdentity.getQName().getLocalName());
+            final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
+            if (baseIdentities.size() == 0) {
+                //no base - abstract
+                final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
+                        BaseIdentity.class.getSimpleName());
                 newType.setExtendsType(gto.toInstance());
-                generatedIdentities.put(baseIdentity.getQName(), gto);
+            } else {
+                //one base - inheritance
+                final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next();
+                GeneratedTOBuilder baseType = resolveIdentitySchemaNode(basePackageName, schemaContext,
+                    baseIdentity, module, verboseClassComments, genCtx);
+                newType.setExtendsType(baseType.toInstance());
             }
 
-            //FIXME: more bases - possible composition, multiple inheritance not possible
-        }
-        generatedIdentities.put(identity.getQName(), newType);
-
-        newType.setAbstract(true);
-        newType.addComment(identity.getDescription());
-        newType.setDescription(createDescription(identity, newType.getFullyQualifiedName(), schemaContext,
-                verboseClassComments, BindingNamespaceType.Identity));
-        newType.setReference(identity.getReference());
-        newType.setModuleName(module.getName());
-        newType.setSchemaPath((List) identity.getPath().getPathFromRoot());
+            newType.setAbstract(true);
+            newType.addComment(identity.getDescription());
+            newType.setDescription(createDescription(identity, newType.getFullyQualifiedName(), schemaContext,
+                    verboseClassComments, BindingNamespaceType.Identity));
+            newType.setReference(identity.getReference());
+            newType.setModuleName(module.getName());
+            newType.setSchemaPath((List) identity.getPath().getPathFromRoot());
 
-        qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
+            qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
 
-        genCtx.get(module).addIdentityType(identity.getQName(), newType);
-        return genCtx;
+            genCtx.get(module).addIdentityType(identity.getQName(), newType);
+        }
+        return newType;
     }
 }