Merge "BUG-869: added proper handling of nullable parameter"
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingGeneratorImpl.java
index f04b748e5bd27977fd6e12fa680109f431d52489..af67e659b3405b72f101a35cf57785398b64e495 100644 (file)
@@ -11,7 +11,6 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.computeDefaultSUID;
-import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.moduleNamespaceToPackageName;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.parseToValidParamName;
 import static org.opendaylight.yangtools.binding.generator.util.BindingTypes.DATA_OBJECT;
@@ -26,7 +25,6 @@ import static org.opendaylight.yangtools.binding.generator.util.Types.VOID;
 import static org.opendaylight.yangtools.binding.generator.util.Types.typeForClass;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
-import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findOriginal;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
 import com.google.common.base.Splitter;
@@ -78,6 +76,7 @@ import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
@@ -106,9 +105,28 @@ import org.slf4j.LoggerFactory;
 
 public class BindingGeneratorImpl implements BindingGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+    private static final Splitter BSDOT_SPLITTER = Splitter.on("\\.");
+    private static final char NEW_LINE = '\n';
+
+    /**
+     * Constant with the concrete name of identifier.
+     */
+    private static final String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+
+    /**
+     * Constant with the concrete name of namespace.
+     */
+    private static final String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
 
     private final Map<Module, ModuleContext> genCtx = new HashMap<>();
 
+    /**
+     * When set to true, generated classes will include javadoc comments which
+     * are useful for users.
+     */
+    private final boolean verboseClassComments;
+
     /**
      * Outer key represents the package name. Outer value represents map of all
      * builders in the same package. Inner key represents the schema node name
@@ -129,14 +147,23 @@ public class BindingGeneratorImpl implements BindingGenerator {
     private SchemaContext schemaContext;
 
     /**
-     * Constant with the concrete name of namespace.
+     * Create a new binding generator with verboe comments.
+     *
+     * @deprecated Use {@link #BindingGeneratorImpl(boolean)} instead.
      */
-    private final static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
+    @Deprecated
+    public BindingGeneratorImpl() {
+        this(true);
+    }
 
     /**
-     * Constant with the concrete name of identifier.
+     * Create a new binding generator.
+     *
+     * @param verboseClassComments generate verbose comments
      */
-    private final static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
+    public BindingGeneratorImpl(final boolean verboseClassComments) {
+        this.verboseClassComments = verboseClassComments;
+    }
 
     /**
      * Resolves generated types from <code>context</code> schema nodes of all
@@ -157,7 +184,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             if <code>context</code> contain no modules
      */
     @Override
-    public List<Type> generateTypes(SchemaContext context) {
+    public List<Type> generateTypes(final SchemaContext context) {
         checkArgument(context != null, "Schema Context reference cannot be NULL.");
         checkState(context.getModules() != null, "Schema Context does not contain defined modules.");
         schemaContext = context;
@@ -195,7 +222,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             if <code>context</code> contain no modules
      */
     @Override
-    public List<Type> generateTypes(SchemaContext context, Set<Module> modules) {
+    public List<Type> generateTypes(final SchemaContext context, final Set<Module> modules) {
         checkArgument(context != null, "Schema Context reference cannot be NULL.");
         checkState(context.getModules() != null, "Schema Context does not contain defined modules.");
         checkArgument(modules != null, "Set of Modules cannot be NULL.");
@@ -227,7 +254,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return filteredGenTypes;
     }
 
-    private void moduleToGenTypes(Module m, SchemaContext context) {
+    private void moduleToGenTypes(final Module m, final SchemaContext context) {
         genCtx.put(m, new ModuleContext());
         allTypeDefinitionsToGenTypes(m);
         groupingsToGenTypes(m, m.getGroupings());
@@ -238,7 +265,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         if (!m.getChildNodes().isEmpty()) {
             final GeneratedTypeBuilder moduleType = moduleToDataType(m);
             genCtx.get(m).addModuleNode(moduleType);
-            final String basePackageName = moduleNamespaceToPackageName(m);
+            final String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
             resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.getChildNodes());
         }
     }
@@ -257,7 +284,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if set of type definitions from module is null
      */
-    private void allTypeDefinitionsToGenTypes(Module module) {
+    private void allTypeDefinitionsToGenTypes(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
         checkArgument(module.getName() != null, "Module name cannot be NULL.");
         final DataNodeIterator it = new DataNodeIterator(module);
@@ -275,24 +302,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private GeneratedTypeBuilder processDataSchemaNode(Module module, String basePackageName,
-            GeneratedTypeBuilder childOf, DataSchemaNode node) {
+    private GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder childOf, final DataSchemaNode node) {
         if (node.isAugmenting() || node.isAddedByUses()) {
             return null;
         }
         final String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
-        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf);
+        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module);
         genType.addComment(node.getDescription());
+        genType.setDescription(createDescription(node, genType.getFullyQualifiedName()));
+        genType.setModuleName(module.getName());
+        genType.setReference(node.getReference());
+        genType.setSchemaPath(node.getPath().getPathFromRoot());
         if (node instanceof DataNodeContainer) {
-            genCtx.get(module).addChildNodeType(node.getPath(), genType);
+            genCtx.get(module).addChildNodeType(node, genType);
             groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
             processUsesAugments((DataNodeContainer) node, module);
         }
         return genType;
     }
 
-    private void containerToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
-            GeneratedTypeBuilder childOf, ContainerSchemaNode node) {
+    private void containerToGenType(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
         if (genType != null) {
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType);
@@ -300,8 +331,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void listToGenType(Module module, String basePackageName, GeneratedTypeBuilder parent,
-            GeneratedTypeBuilder childOf, ListSchemaNode node) {
+    private void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder parent,
+            final GeneratedTypeBuilder childOf, final ListSchemaNode node) {
         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node);
         if (genType != null) {
             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), Types.listTypeFor(genType));
@@ -333,8 +364,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void processUsesAugments(DataNodeContainer node, Module module) {
-        final String basePackageName = moduleNamespaceToPackageName(module);
+    private void processUsesAugments(final DataNodeContainer node, final Module module) {
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         for (UsesNode usesNode : node.getUses()) {
             for (AugmentationSchema augment : usesNode.getAugmentations()) {
                 usesAugmentationToGenTypes(basePackageName, augment, module, usesNode, node);
@@ -358,12 +389,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if set of augmentations from module is null
      */
-    private void allAugmentsToGenTypes(Module module) {
+    private void allAugmentsToGenTypes(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
         checkArgument(module.getName() != null, "Module name cannot be NULL.");
         checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
 
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final List<AugmentationSchema> augmentations = resolveAugmentations(module);
         for (AugmentationSchema augment : augmentations) {
             augmentationToGenTypes(basePackageName, augment, module);
@@ -384,7 +415,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if set of module augmentations is null
      */
-    private List<AugmentationSchema> resolveAugmentations(Module module) {
+    private List<AugmentationSchema> resolveAugmentations(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
         checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
 
@@ -405,13 +436,15 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalArgumentException
      *             if module is null
      */
-    private GeneratedTypeBuilder moduleToDataType(Module module) {
+    private GeneratedTypeBuilder moduleToDataType(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
 
         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
         addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
         moduleDataTypeBuilder.addImplementsType(DATA_ROOT);
         moduleDataTypeBuilder.addComment(module.getDescription());
+        moduleDataTypeBuilder.setDescription(createDescription(module));
+        moduleDataTypeBuilder.setReference(module.getReference());
         return moduleDataTypeBuilder;
     }
 
@@ -431,7 +464,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if set of rpcs from module is null
      */
-    private void rpcMethodsToGenType(Module module) {
+    private void rpcMethodsToGenType(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
         checkArgument(module.getName() != null, "Module name cannot be NULL.");
         final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
@@ -440,9 +473,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
             return;
         }
 
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
         interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
+        interfaceBuilder.setDescription(createDescription(rpcDefinitions, module.getName(), module.getModuleSourcePath()));
+
         for (RpcDefinition rpc : rpcDefinitions) {
             if (rpc != null) {
                 final String rpcName = BindingMapping.getClassName(rpc.getQName());
@@ -458,7 +493,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     inType.addImplementsType(DATA_OBJECT);
                     inType.addImplementsType(augmentable(inType));
                     resolveDataSchemaNodes(module, basePackageName, inType, inType, input.getChildNodes());
-                    genCtx.get(module).addChildNodeType(input.getPath(), inType);
+                    genCtx.get(module).addChildNodeType(input, inType);
                     final GeneratedType inTypeInstance = inType.toInstance();
                     method.addParameter(inTypeInstance, "input");
                 }
@@ -470,7 +505,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     outType.addImplementsType(DATA_OBJECT);
                     outType.addImplementsType(augmentable(outType));
                     resolveDataSchemaNodes(module, basePackageName, outType, outType, output.getChildNodes());
-                    genCtx.get(module).addChildNodeType(output.getPath(), outType);
+                    genCtx.get(module).addChildNodeType(output, outType);
                     outTypeInstance = outType.toInstance();
                 }
 
@@ -499,7 +534,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if set of notifications from module is null
      */
-    private void notificationsToGenType(Module module) {
+    private void notificationsToGenType(final Module module) {
         checkArgument(module != null, "Module reference cannot be NULL.");
         checkArgument(module.getName() != null, "Module name cannot be NULL.");
         final Set<NotificationDefinition> notifications = module.getNotifications();
@@ -510,26 +545,29 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener");
         listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+
+
 
         for (NotificationDefinition notification : notifications) {
             if (notification != null) {
                 processUsesAugments(notification, module);
 
                 final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName,
-                        notification, BindingTypes.DATA_OBJECT);
+                        notification, BindingTypes.DATA_OBJECT, module);
                 notificationInterface.addImplementsType(NOTIFICATION);
-                genCtx.get(module).addChildNodeType(notification.getPath(), notificationInterface);
+                genCtx.get(module).addChildNodeType(notification, notificationInterface);
 
                 // Notification object
                 resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface,
                         notification.getChildNodes());
 
                 listenerInterface.addMethod("on" + notificationInterface.getName())
-                        .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
-                        .setComment(notification.getDescription()).setReturnType(Types.VOID);
+                .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
+                .setComment(notification.getDescription()).setReturnType(Types.VOID);
             }
         }
+        listenerInterface.setDescription(createDescription(notifications, module.getName(), module.getModuleSourcePath()));
 
         genCtx.get(module).addTopLevelNodeType(listenerInterface);
     }
@@ -546,9 +584,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            {@link identityToGenType}
      *
      */
-    private void allIdentitiesToGenTypes(Module module, SchemaContext context) {
+    private void allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
-        final String basePackageName = moduleNamespaceToPackageName(module);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
 
         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
             for (IdentitySchemaNode identity : schemaIdentities) {
@@ -576,14 +614,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            information about base of identity
      *
      */
-    private void identityToGenType(Module module, String basePackageName, IdentitySchemaNode identity,
-            SchemaContext context) {
+    private void identityToGenType(final Module module, final String basePackageName,
+            final IdentitySchemaNode identity, final SchemaContext context) {
         if (identity == null) {
             return;
         }
         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
         final String genTypeName = BindingMapping.getClassName(identity.getQName());
-        final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
+        final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
         final IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
         if (baseIdentity == null) {
             final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
@@ -591,21 +629,28 @@ public class BindingGeneratorImpl implements BindingGenerator {
             newType.setExtendsType(gto.toInstance());
         } else {
             final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
-            final String returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
+            final String returnTypePkgName = BindingMapping.getRootPackageName(baseIdentityParentModule
+                    .getQNameModule());
             final String returnTypeName = BindingMapping.getClassName(baseIdentity.getQName());
             final GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName)
-                    .toInstance();
+            .toInstance();
             newType.setExtendsType(gto);
         }
         newType.setAbstract(true);
         newType.addComment(identity.getDescription());
+        newType.setDescription(createDescription(identity, newType.getFullyQualifiedName()));
+        newType.setReference(identity.getReference());
+        newType.setModuleName(module.getName());
+        newType.setSchemaPath(identity.getPath().getPathFromRoot());
+
         final QName qname = identity.getQName();
         qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, qname);
 
         genCtx.get(module).addIdentityType(identity.getQName(), newType);
     }
 
-    private static Constant qnameConstant(GeneratedTypeBuilderBase<?> toBuilder, String constantName, QName name) {
+    private static Constant qnameConstant(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
+            final QName name) {
         StringBuilder sb = new StringBuilder("org.opendaylight.yangtools.yang.common.QName");
         sb.append(".create(");
         sb.append('"');
@@ -632,10 +677,10 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            of groupings from which types will be generated
      *
      */
-    private void groupingsToGenTypes(Module module, Collection<GroupingDefinition> groupings) {
-        final String basePackageName = moduleNamespaceToPackageName(module);
+    private void groupingsToGenTypes(final Module module, final Collection<GroupingDefinition> groupings) {
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
-                .sort(groupings);
+        .sort(groupings);
         for (GroupingDefinition grouping : groupingsSortedByDependencies) {
             groupingToGenType(basePackageName, grouping, module);
         }
@@ -655,9 +700,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return GeneratedType which is generated from grouping (object of type
      *         <code>GroupingDefinition</code>)
      */
-    private void groupingToGenType(String basePackageName, GroupingDefinition grouping, Module module) {
+    private void groupingToGenType(final String basePackageName, final GroupingDefinition grouping, final Module module) {
         final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath());
-        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping);
+        final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, grouping, module);
         genCtx.get(module).addGroupingType(grouping.getPath(), genType);
         resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes());
         groupingsToGenTypes(module, grouping.getGroupings());
@@ -681,12 +726,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return enumeration builder which contains data from
      *         <code>enumTypeDef</code>
      */
-    private EnumBuilder resolveInnerEnumFromTypeDefinition(EnumTypeDefinition enumTypeDef, QName enumName,
-            GeneratedTypeBuilder typeBuilder) {
+    private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName,
+            final GeneratedTypeBuilder typeBuilder) {
         if ((enumTypeDef != null) && (typeBuilder != null) && (enumTypeDef.getQName() != null)
                 && (enumTypeDef.getQName().getLocalName() != null)) {
             final String enumerationName = BindingMapping.getClassName(enumName);
             final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+            enumBuilder.setDescription(enumTypeDef.getDescription());
             enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
             return enumBuilder;
         }
@@ -707,11 +753,17 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalArgumentException
      *             if <code>module</code> is null
      */
-    private GeneratedTypeBuilder moduleTypeBuilder(Module module, String postfix) {
+    private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
         checkArgument(module != null, "Module reference cannot be NULL.");
-        final String packageName = moduleNamespaceToPackageName(module);
+        final String packageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
-        return new GeneratedTypeBuilderImpl(packageName, moduleName);
+
+        final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
+        moduleBuilder.setDescription(createDescription(module));
+        moduleBuilder.setReference(module.getReference());
+        moduleBuilder.setModuleName(moduleName);
+
+        return moduleBuilder;
     }
 
     /**
@@ -738,7 +790,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @throws IllegalStateException
      *             if augment target path is null
      */
-    private void augmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module) {
+    private void augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema,
+            final Module module) {
         checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
         checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
         checkState(augSchema.getTargetPath() != null,
@@ -750,9 +803,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
         if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-            targetSchemaNode = findOriginal((DataSchemaNode) targetSchemaNode, schemaContext);
+            if (targetSchemaNode instanceof DerivableSchemaNode) {
+                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+            }
             if (targetSchemaNode == null) {
-                throw new NullPointerException("Failed to find target node from grouping in augmentation " + augSchema
+                throw new IllegalStateException("Failed to find target node from grouping in augmentation " + augSchema
                         + " in module " + module.getName());
             }
         }
@@ -780,8 +835,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void usesAugmentationToGenTypes(String augmentPackageName, AugmentationSchema augSchema, Module module,
-            UsesNode usesNode, DataNodeContainer usesNodeParent) {
+    private void usesAugmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema,
+            final Module module, final UsesNode usesNode, final DataNodeContainer usesNodeParent) {
         checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
         checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
         checkState(augSchema.getTargetPath() != null,
@@ -825,7 +880,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            parent of uses node
      * @return node from its original location in grouping
      */
-    private DataSchemaNode findOriginalTargetFromGrouping(SchemaPath targetPath, UsesNode parentUsesNode) {
+    private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) {
         SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.getGroupingPath()
                 .getPathFromRoot());
         if (!(targetGrouping instanceof GroupingDefinition)) {
@@ -885,8 +940,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            and uses of augment
      * @return generated type builder for augment
      */
-    private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(Module module, String augmentPackageName,
-            String basePackageName, Type targetTypeRef, AugmentationSchema augSchema) {
+    private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
+            final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema) {
         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
         if (augmentBuilders == null) {
             augmentBuilders = new HashMap<>();
@@ -910,9 +965,12 @@ public class BindingGeneratorImpl implements BindingGenerator {
         augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.getChildNodes());
         augmentBuilders.put(augTypeName, augTypeBuilder);
 
-        genCtx.get(module).addTargetToAugmentation(targetTypeRef, augTypeBuilder);
+        if(!augSchema.getChildNodes().isEmpty()) {
+            genCtx.get(module).addTargetToAugmentation(targetTypeRef, augTypeBuilder);
+            genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
+
+        }
         genCtx.get(module).addAugmentType(augTypeBuilder);
-        genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
         return augTypeBuilder;
     }
 
@@ -921,7 +979,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @param unknownSchemaNodes
      * @return nodeParameter of UnknownSchemaNode
      */
-    private String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
+    private String getAugmentIdentifier(final List<UnknownSchemaNode> unknownSchemaNodes) {
         for (UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
             final QName nodeType = unknownSchemaNode.getNodeType();
             if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName())
@@ -944,7 +1002,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            string with name of augmented node
      * @return string with unique name for augmentation builder
      */
-    private String augGenTypeName(Map<String, GeneratedTypeBuilder> builders, String genTypeName) {
+    private String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
         int index = 1;
         if (builders != null) {
             while (builders.containsKey(genTypeName + index)) {
@@ -979,9 +1037,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         parameter. The getter methods (representing child nodes) could be
      *         added to it.
      */
-    private GeneratedTypeBuilder resolveDataSchemaNodes(Module module, String basePackageName,
-            GeneratedTypeBuilder parent, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
-        if ((schemaNodes != null) && (parent != null)) {
+    private GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final Iterable<DataSchemaNode> schemaNodes) {
+        if (schemaNodes != null && parent != null) {
             for (DataSchemaNode schemaNode : schemaNodes) {
                 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
@@ -1013,8 +1071,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         parameter <code>typeBuilder</code>. The getter method could be
      *         added to it.
      */
-    private GeneratedTypeBuilder augSchemaNodeToMethods(Module module, String basePackageName,
-            GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Set<DataSchemaNode> schemaNodes) {
+    private GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
+            final Iterable<DataSchemaNode> schemaNodes) {
         if ((schemaNodes != null) && (typeBuilder != null)) {
             for (DataSchemaNode schemaNode : schemaNodes) {
                 if (!schemaNode.isAugmenting()) {
@@ -1042,8 +1101,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @param module
      *            current module
      */
-    private void addSchemaNodeToBuilderAsMethod(String basePackageName, DataSchemaNode node,
-            GeneratedTypeBuilder typeBuilder, GeneratedTypeBuilder childOf, Module module) {
+    private void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
+            final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module) {
         if (node != null && typeBuilder != null) {
             if (node instanceof LeafSchemaNode) {
                 resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) node);
@@ -1057,7 +1116,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 choiceToGeneratedType(module, basePackageName, typeBuilder, (ChoiceNode) node);
             } else {
                 // TODO: anyxml not yet supported
-                LOG.warn("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(),
+                LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(),
                         typeBuilder.getFullyQualifiedName());
             }
         }
@@ -1086,8 +1145,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>choiceNode</code> is null</li>
      *             </ul>
      */
-    private void choiceToGeneratedType(Module module, String basePackageName, GeneratedTypeBuilder parent,
-            ChoiceNode choiceNode) {
+    private void choiceToGeneratedType(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final ChoiceNode choiceNode) {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
 
@@ -1097,7 +1156,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
             constructGetter(parent, choiceNode.getQName().getLocalName(), choiceNode.getDescription(),
                     choiceTypeBuilder);
             choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
-            genCtx.get(module).addChildNodeType(choiceNode.getPath(), choiceTypeBuilder);
+            genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
             generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
         }
     }
@@ -1129,8 +1188,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>caseNodes</code> equals null</li>
      *             </ul>
      */
-    private void generateTypesFromChoiceCases(Module module, String basePackageName, Type refChoiceType,
-            ChoiceNode choiceNode) {
+    private void generateTypesFromChoiceCases(final Module module, final String basePackageName,
+            final Type refChoiceType, final ChoiceNode choiceNode) {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL.");
         checkArgument(choiceNode != null, "ChoiceNode cannot be NULL.");
@@ -1143,11 +1202,11 @@ public class BindingGeneratorImpl implements BindingGenerator {
         for (ChoiceCaseNode caseNode : caseNodes) {
             if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
                 caseTypeBuilder.addImplementsType(refChoiceType);
                 genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
                 genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
-                final Set<DataSchemaNode> caseChildNodes = caseNode.getChildNodes();
+                final Iterable<DataSchemaNode> caseChildNodes = caseNode.getChildNodes();
                 if (caseChildNodes != null) {
                     Object parentNode = null;
                     final SchemaPath nodeSp = choiceNode.getPath();
@@ -1160,11 +1219,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
                         if (targetSchemaNode instanceof DataSchemaNode
                                 && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-                            targetSchemaNode = findOriginal((DataSchemaNode) targetSchemaNode, schemaContext);
+                            if (targetSchemaNode instanceof DerivableSchemaNode) {
+                                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orNull();
+                            }
                             if (targetSchemaNode == null) {
-                                throw new NullPointerException(
+                                throw new IllegalStateException(
                                         "Failed to find target node from grouping for augmentation " + augSchema
-                                                + " in module " + module.getName());
+                                        + " in module " + module.getName());
                             }
                         }
                         parent = targetSchemaNode;
@@ -1173,6 +1234,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
                         parent = findDataSchemaNode(schemaContext, sp.getParent());
                     }
                     GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
+                    if (childOfType == null) {
+                        childOfType = findGroupingByPath(parent.getPath());
+                    }
                     resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
                 }
             }
@@ -1208,8 +1272,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>augmentedNodes</code> is null</li>
      *             </ul>
      */
-    private void generateTypesFromAugmentedChoiceCases(Module module, String basePackageName, Type targetType,
-            ChoiceNode targetNode, Set<DataSchemaNode> augmentedNodes) {
+    private void generateTypesFromAugmentedChoiceCases(final Module module, final String basePackageName,
+            final Type targetType, final ChoiceNode targetNode, final Iterable<DataSchemaNode> augmentedNodes) {
         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
         checkArgument(targetType != null, "Referenced Choice Type cannot be NULL.");
         checkArgument(augmentedNodes != null, "Set of Choice Case Nodes cannot be NULL.");
@@ -1217,7 +1281,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         for (DataSchemaNode caseNode : augmentedNodes) {
             if (caseNode != null) {
                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
                 caseTypeBuilder.addImplementsType(targetType);
 
                 SchemaNode parent = null;
@@ -1226,7 +1290,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
                 GeneratedTypeBuilder childOfType = null;
                 if (parent instanceof Module) {
-                    childOfType = genCtx.get((Module) parent).getModuleNode();
+                    childOfType = genCtx.get(parent).getModuleNode();
                 } else if (parent instanceof ChoiceCaseNode) {
                     childOfType = findCaseByPath(parent.getPath());
                 } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
@@ -1245,7 +1309,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                 } else {
                     node = targetNode.getCaseNodeByName(caseNode.getQName().getLocalName());
                 }
-                final Set<DataSchemaNode> childNodes = node.getChildNodes();
+                final Iterable<DataSchemaNode> childNodes = node.getChildNodes();
                 if (childNodes != null) {
                     resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
                 }
@@ -1272,7 +1336,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         <li>true - in other cases</li>
      *         </ul>
      */
-    private Type resolveLeafSchemaNodeAsMethod(GeneratedTypeBuilder typeBuilder, LeafSchemaNode leaf) {
+    private Type resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
         Type returnType = null;
         if ((leaf != null) && (typeBuilder != null)) {
             final String leafName = leaf.getQName().getLocalName();
@@ -1297,14 +1361,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     }
                     ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
                 } else if (typeDef instanceof UnionType) {
-                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
                     if (genTOBuilder != null) {
                         returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
                     }
                 } else if (typeDef instanceof BitsTypeDefinition) {
-                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf);
+                    genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
                     if (genTOBuilder != null) {
-                        returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
+                        returnType = genTOBuilder.toInstance();
                     }
                 } else {
                     final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
@@ -1319,19 +1383,20 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return returnType;
     }
 
-    private void processContextRefExtension(LeafSchemaNode leaf, MethodSignatureBuilder getter, Module module) {
+    private void processContextRefExtension(final LeafSchemaNode leaf, final MethodSignatureBuilder getter,
+            final Module module) {
         for (UnknownSchemaNode node : leaf.getUnknownSchemaNodes()) {
             final QName nodeType = node.getNodeType();
             if ("context-reference".equals(nodeType.getLocalName())) {
                 final String nodeParam = node.getNodeParameter();
                 IdentitySchemaNode identity = null;
                 String basePackageName = null;
-                final Iterable<String> splittedElement = Splitter.on(':').split(nodeParam);
+                final Iterable<String> splittedElement = COLON_SPLITTER.split(nodeParam);
                 final Iterator<String> iterator = splittedElement.iterator();
                 final int length = Iterables.size(splittedElement);
                 if (length == 1) {
                     identity = findIdentityByName(module.getIdentities(), iterator.next());
-                    basePackageName = moduleNamespaceToPackageName(module);
+                    basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
                 } else if (length == 2) {
                     String prefix = iterator.next();
                     final Module dependentModule = findModuleFromImports(module.getImports(), prefix);
@@ -1340,7 +1405,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
                                 + prefix);
                     }
                     identity = findIdentityByName(dependentModule.getIdentities(), iterator.next());
-                    basePackageName = moduleNamespaceToPackageName(dependentModule);
+                    basePackageName = BindingMapping.getRootPackageName(dependentModule.getQNameModule());
                 } else {
                     throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
                             + nodeParam);
@@ -1360,7 +1425,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private IdentitySchemaNode findIdentityByName(Set<IdentitySchemaNode> identities, String name) {
+    private IdentitySchemaNode findIdentityByName(final Set<IdentitySchemaNode> identities, final String name) {
         for (IdentitySchemaNode id : identities) {
             if (id.getQName().getLocalName().equals(name)) {
                 return id;
@@ -1369,7 +1434,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null;
     }
 
-    private Module findModuleFromImports(Set<ModuleImport> imports, String prefix) {
+    private Module findModuleFromImports(final Set<ModuleImport> imports, final String prefix) {
         for (ModuleImport imp : imports) {
             if (imp.getPrefix().equals(prefix)) {
                 return schemaContext.findModuleByName(imp.getModuleName(), imp.getRevision());
@@ -1378,8 +1443,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null;
     }
 
-    private boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf,
-            boolean isReadOnly, Module module) {
+    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
+            final boolean isReadOnly, final Module module) {
         if ((leaf != null) && (toBuilder != null)) {
             final String leafName = leaf.getQName().getLocalName();
             String leafDesc = leaf.getDescription();
@@ -1394,13 +1459,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     // GeneratedType for this type definition should be already
                     // created
                     QName qname = typeDef.getQName();
-                    Module unionModule = null;
-                    String prefix = qname.getPrefix();
-                    if (prefix == null || prefix.isEmpty() || prefix.equals(module.getPrefix())) {
-                        unionModule = module;
-                    } else {
-                        unionModule = findModuleFromImports(module.getImports(), qname.getPrefix());
-                    }
+                    Module unionModule = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(),
+                            qname.getRevision());
                     final ModuleContext mc = genCtx.get(unionModule);
                     returnType = mc.getTypedefs().get(typeDef.getPath());
                 } else {
@@ -1433,8 +1493,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         <li>true - other cases</li>
      *         </ul>
      */
-    private boolean resolveLeafSchemaNodeAsProperty(GeneratedTOBuilder toBuilder, LeafSchemaNode leaf, Type returnType,
-            boolean isReadOnly) {
+    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
+            final Type returnType, final boolean isReadOnly) {
         if (returnType == null) {
             return false;
         }
@@ -1467,7 +1527,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         <li>false - other cases</li>
      *         </ul>
      */
-    private boolean resolveLeafListSchemaNode(GeneratedTypeBuilder typeBuilder, LeafListSchemaNode node) {
+    private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node) {
         if ((node != null) && (typeBuilder != null)) {
             final QName nodeName = node.getQName();
 
@@ -1484,13 +1544,13 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
                     ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType);
                 } else if (typeDef instanceof UnionType) {
-                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node);
+                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);
                     if (genTOBuilder != null) {
                         returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
                     }
                 } else if (typeDef instanceof BitsTypeDefinition) {
-                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node);
-                    returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
+                    final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule);
+                    returnType = genTOBuilder.toInstance();
                 } else {
                     final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);
@@ -1504,10 +1564,16 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return false;
     }
 
-    private Type createReturnTypeForUnion(GeneratedTOBuilder genTOBuilder, TypeDefinition<?> typeDef,
-            GeneratedTypeBuilder typeBuilder, Module parentModule) {
+    private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final TypeDefinition<?> typeDef,
+            final GeneratedTypeBuilder typeBuilder, final Module parentModule) {
         final GeneratedTOBuilderImpl returnType = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
                 genTOBuilder.getName());
+
+        returnType.setDescription(typeDef.getDescription());
+        returnType.setReference(typeDef.getReference());
+        returnType.setSchemaPath(typeDef.getPath().getPathFromRoot());
+        returnType.setModuleName(parentModule.getName());
+
         genTOBuilder.setTypedef(true);
         genTOBuilder.setIsUnion(true);
         ((TypeProviderImpl) typeProvider).addUnitsToGenTO(genTOBuilder, typeDef.getUnits());
@@ -1532,8 +1598,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return returnType.toInstance();
     }
 
-    private GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode) {
-        return addDefaultInterfaceDefinition(packageName, schemaNode, null);
+    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final Module module) {
+        return addDefaultInterfaceDefinition(packageName, schemaNode, null, module);
     }
 
     /**
@@ -1559,7 +1626,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            parent type (can be null)
      * @return generated type builder <code>schemaNode</code>
      */
-    private GeneratedTypeBuilder addDefaultInterfaceDefinition(String packageName, SchemaNode schemaNode, Type parent) {
+    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final Type parent, final Module module) {
         final GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, "");
         if (parent == null) {
             it.addImplementsType(DATA_OBJECT);
@@ -1571,6 +1639,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
 
         if (schemaNode instanceof DataNodeContainer) {
+            groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
             addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
         }
 
@@ -1587,7 +1656,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            schema node which provide data about the schema node name
      * @return generated type builder for <code>schemaNode</code>
      */
-    private GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode) {
+    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
         return addRawInterfaceDefinition(packageName, schemaNode, "");
     }
 
@@ -1616,7 +1685,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             </ul>
      *
      */
-    private GeneratedTypeBuilder addRawInterfaceDefinition(String packageName, SchemaNode schemaNode, String prefix) {
+    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final String prefix) {
         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
         checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
         checkArgument(schemaNode.getQName() != null, "QName for Data Schema Node cannot be NULL.");
@@ -1632,8 +1702,14 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         // FIXME: Validation of name conflict
         final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
+        final Module module = findParentModule(schemaContext, schemaNode);
         qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
         newType.addComment(schemaNode.getDescription());
+        newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName()));
+        newType.setReference(schemaNode.getReference());
+        newType.setSchemaPath(schemaNode.getPath().getPathFromRoot());
+        newType.setModuleName(module.getName());
+
         if (!genTypeBuilders.containsKey(packageName)) {
             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
             builders.put(genTypeName, newType);
@@ -1657,7 +1733,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return string with the name of the getter method for
      *         <code>methodName</code> in JAVA method format
      */
-    public static String getterMethodName(String localName, Type returnType) {
+    public static String getterMethodName(final String localName, final Type returnType) {
         final StringBuilder method = new StringBuilder();
         if (BOOLEAN.equals(returnType)) {
             method.append("is");
@@ -1690,8 +1766,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @return method signature builder which represents the getter method of
      *         <code>interfaceBuilder</code>
      */
-    private MethodSignatureBuilder constructGetter(GeneratedTypeBuilder interfaceBuilder, String schemaNodeName,
-            String comment, Type returnType) {
+    private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
+            final String schemaNodeName, final String comment, final Type returnType) {
         final MethodSignatureBuilder getMethod = interfaceBuilder
                 .addMethod(getterMethodName(schemaNodeName, returnType));
         getMethod.setComment(comment);
@@ -1723,8 +1799,9 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *             <li>if <code>typeBuilder</code> equals null</li>
      *             </ul>
      */
-    private void addSchemaNodeToListBuilders(String basePackageName, DataSchemaNode schemaNode,
-            GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder, List<String> listKeys, Module module) {
+    private void addSchemaNodeToListBuilders(final String basePackageName, final DataSchemaNode schemaNode,
+            final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys,
+            final Module module) {
         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
 
@@ -1752,7 +1829,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
         }
     }
 
-    private void typeBuildersToGenTypes(Module module, GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
+    private void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
+            final GeneratedTOBuilder genTOBuilder) {
         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
 
         if (genTOBuilder != null) {
@@ -1796,7 +1874,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *         <code>list</code> or null if <code>list</code> is null or list of
      *         key definitions is null or empty.
      */
-    private GeneratedTOBuilder resolveListKeyTOBuilder(String packageName, ListSchemaNode list) {
+    private GeneratedTOBuilder resolveListKeyTOBuilder(final String packageName, final ListSchemaNode list) {
         GeneratedTOBuilder genTOBuilder = null;
         if ((list.getKeyDefinition() != null) && (!list.getKeyDefinition().isEmpty())) {
             final String listName = list.getQName().getLocalName() + "Key";
@@ -1828,8 +1906,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      * @param leaf
      * @return generated TO builder for <code>typeDef</code>
      */
-    private GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
-            DataSchemaNode leaf) {
+    private GeneratedTOBuilder addTOToTypeBuilder(final TypeDefinition<?> typeDef,
+            final GeneratedTypeBuilder typeBuilder, final DataSchemaNode leaf, final Module parentModule) {
         final String classNameFromLeaf = BindingMapping.getClassName(leaf.getQName());
         final List<GeneratedTOBuilder> genTOBuilders = new ArrayList<>();
         final String packageName = typeBuilder.getFullyQualifiedName();
@@ -1855,7 +1933,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
 
         } else if (typeDef instanceof BitsTypeDefinition) {
             genTOBuilders.add((((TypeProviderImpl) typeProvider)).provideGeneratedTOBuilderForBitsTypeDefinition(
-                    packageName, typeDef, classNameFromLeaf));
+                    packageName, typeDef, classNameFromLeaf, parentModule.getName()));
         }
         if (genTOBuilders != null && !genTOBuilders.isEmpty()) {
             for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
@@ -1883,8 +1961,8 @@ public class BindingGeneratorImpl implements BindingGenerator {
      *            <code>dataNodeContainer</code>
      * @return generated type builder with all implemented types
      */
-    private GeneratedTypeBuilder addImplementedInterfaceFromUses(DataNodeContainer dataNodeContainer,
-            GeneratedTypeBuilder builder) {
+    private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
+            final GeneratedTypeBuilder builder) {
         for (UsesNode usesNode : dataNodeContainer.getUses()) {
             if (usesNode.getGroupingPath() != null) {
                 final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath()).toInstance();
@@ -1892,14 +1970,158 @@ public class BindingGeneratorImpl implements BindingGenerator {
                     throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
                             + builder.getName());
                 }
+
                 builder.addImplementsType(genType);
-                builder.addComment(genType.getComment());
+                /*
+                builder.addComment(genType.getDescription());
+                builder.setDescription(genType.getDescription());
+                builder.setModuleName(genType.getModuleName());
+                builder.setReference(genType.getReference());
+                builder.setSchemaPath(genType.getSchemaPath());
+                */
             }
         }
         return builder;
     }
 
-    private GeneratedTypeBuilder findChildNodeByPath(SchemaPath path) {
+    private boolean isNullOrEmpty(final Collection<?> list) {
+        return (list == null || list.isEmpty() ? true : false);
+    }
+
+    private String createDescription(final Set<? extends SchemaNode> schemaNodes, final String moduleName, final String moduleSourcePath) {
+        final StringBuilder sb = new StringBuilder();
+
+        if (!isNullOrEmpty(schemaNodes)) {
+            final SchemaNode node = schemaNodes.iterator().next();
+
+            if (node instanceof RpcDefinition) {
+                sb.append("Interface for implementing the following YANG RPCs defined in module <b>" + moduleName + "</b>");
+            } else if (node instanceof NotificationDefinition) {
+                sb.append("Interface for receiving the following YANG notifications defined in module <b>" + moduleName + "</b>");
+            }
+        }
+        sb.append(NEW_LINE);
+        sb.append("<br />(Source path: <i>");
+        sb.append(moduleSourcePath);
+        sb.append("</i>):");
+        sb.append(NEW_LINE);
+
+        if (verboseClassComments) {
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(schemaNodes));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+        }
+
+        return sb.toString();
+    }
+
+    private String createDescription(final SchemaNode schemaNode, final String fullyQualifiedName) {
+        final StringBuilder sb = new StringBuilder();
+        final String formattedDescription = YangTemplate.formatToParagraph(schemaNode.getDescription(), 0);
+
+        if (!isNullOrEmpty(formattedDescription)) {
+            sb.append(formattedDescription);
+            sb.append(NEW_LINE);
+        }
+
+        if (verboseClassComments) {
+            final Module module = findParentModule(schemaContext, schemaNode);
+            final StringBuilder linkToBuilderClass = new StringBuilder();
+            final StringBuilder linkToKeyClass = new StringBuilder();
+            final String[] namespace = Iterables.toArray(BSDOT_SPLITTER.split(fullyQualifiedName), String.class);
+            String className = namespace[namespace.length - 1];
+
+            if (hasBuilderClass(schemaNode)) {
+                linkToBuilderClass.append(className);
+                linkToBuilderClass.append("Builder");
+
+                if (schemaNode instanceof ListSchemaNode) {
+                    linkToKeyClass.append(className);
+                    linkToKeyClass.append("Key");
+                }
+            }
+
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />(Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
+            sb.append(NEW_LINE);
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(schemaNode));
+            sb.append("</pre>");
+            sb.append(NEW_LINE);
+            sb.append("The schema path to identify an instance is");
+            sb.append(NEW_LINE);
+            sb.append("<i>");
+            sb.append(YangTemplate.formatSchemaPath(module.getName(), schemaNode.getPath().getPathFromRoot()));
+            sb.append("</i>");
+            sb.append(NEW_LINE);
+
+            if (hasBuilderClass(schemaNode)) {
+                sb.append(NEW_LINE);
+                sb.append("<p>To create instances of this class use " + "{@link " + linkToBuilderClass + "}.");
+                sb.append(NEW_LINE);
+                sb.append("@see ");
+                sb.append(linkToBuilderClass);
+                if (schemaNode instanceof ListSchemaNode) {
+                    sb.append("@see ");
+                    sb.append(linkToKeyClass);
+                }
+                sb.append(NEW_LINE);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    private boolean hasBuilderClass(final SchemaNode schemaNode) {
+        if (schemaNode instanceof ContainerSchemaNode || schemaNode instanceof ListSchemaNode ||
+                schemaNode instanceof RpcDefinition || schemaNode instanceof NotificationDefinition) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isNullOrEmpty(final String string) {
+        return (string == null || string.isEmpty() ? true : false);
+    }
+
+    private String createDescription(final Module module) {
+        final StringBuilder sb = new StringBuilder();
+        final String formattedDescription = YangTemplate.formatToParagraph(module.getDescription(), 0);
+
+        if (!isNullOrEmpty(formattedDescription)) {
+            sb.append(formattedDescription);
+            sb.append(NEW_LINE);
+        }
+
+        if (verboseClassComments) {
+            sb.append("<p>");
+            sb.append("This class represents the following YANG schema fragment defined in module <b>");
+            sb.append(module.getName());
+            sb.append("</b>");
+            sb.append(NEW_LINE);
+            sb.append("<br />Source path: <i>");
+            sb.append(module.getModuleSourcePath());
+            sb.append("</i>):");
+            sb.append(NEW_LINE);
+            sb.append("<pre>");
+            sb.append(NEW_LINE);
+            sb.append(YangTemplate.generateYangSnipet(module));
+            sb.append("</pre>");
+        }
+
+        return sb.toString();
+    }
+
+    private GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path) {
         for (ModuleContext ctx : genCtx.values()) {
             GeneratedTypeBuilder result = ctx.getChildNode(path);
             if (result != null) {
@@ -1909,7 +2131,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null;
     }
 
-    private GeneratedTypeBuilder findGroupingByPath(SchemaPath path) {
+    private GeneratedTypeBuilder findGroupingByPath(final SchemaPath path) {
         for (ModuleContext ctx : genCtx.values()) {
             GeneratedTypeBuilder result = ctx.getGrouping(path);
             if (result != null) {
@@ -1919,7 +2141,7 @@ public class BindingGeneratorImpl implements BindingGenerator {
         return null;
     }
 
-    private GeneratedTypeBuilder findCaseByPath(SchemaPath path) {
+    private GeneratedTypeBuilder findCaseByPath(final SchemaPath path) {
         for (ModuleContext ctx : genCtx.values()) {
             GeneratedTypeBuilder result = ctx.getCase(path);
             if (result != null) {