Split out BindingRuntimeGenerator 43/69943/1
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 2 Mar 2018 17:09:44 +0000 (18:09 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 23 Mar 2018 06:46:50 +0000 (07:46 +0100)
BindingRuntimeContext does not require all of the information
captured in a normal BindingGenerator run, such as constants, comments
and similar.

The fact that we do not have separation between compile-time and
run-time granularity of this data comes from history of the codebase,
when BindingRuntimeContext did not exist in its current form and we
infered much of the information from the classes lazily.

Introduce BindingRuntimeGenerator interface and refactor
BindingGeneratorImpl to reflect this split. This leads to faster
BindingRuntimeContext creation, as the call to generateTypes()
is no longer needed.

JIRA: MDSAL-312
Change-Id: Ibb1c22d4e4c9ff90e37d6e10e258f632a9c87ef5
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 4a558ef0c1b722ee079a2855aabe285c5528ae36)

13 files changed:
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/gen/impl/AbstractStreamWriterGenerator.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/BindingCodecContext.java
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingGenerator.java
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeGenerator.java [new file with mode: 0644]
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeTypes.java [new file with mode: 0644]
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/spi/TypeProvider.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/BindingGeneratorImpl.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/ModuleContext.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/util/BindingRuntimeContext.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/TypeProviderImpl.java

index a54a83513b3dc1ede2c45edf97ec6cce02894430..1b1be4125e065798b6da45a7f8b310cda245e7dc 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.slf4j.Logger;
@@ -163,9 +164,9 @@ abstract class AbstractStreamWriterGenerator extends AbstractGenerator implement
     private DataObjectSerializerSource generateEmitterSource(final Class<?> type, final String serializerName) {
         Types.typeForClass(type);
         javassist.appendClassLoaderIfMissing(type.getClassLoader());
-        final Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(type);
+        final Entry<GeneratedType, WithStatus> typeWithSchema = context.getTypeWithSchema(type);
         final GeneratedType generatedType = typeWithSchema.getKey();
-        final Object schema = typeWithSchema.getValue();
+        final WithStatus schema = typeWithSchema.getValue();
 
         final DataObjectSerializerSource source;
         if (schema instanceof ContainerSchemaNode) {
index 1f6be5360cc9e9f093583ffdfbcd2f2e9f1e1c8a..a6f76a6562f549bf4c60c57295cc97baea74e15f 100644 (file)
@@ -47,6 +47,7 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdent
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
@@ -311,8 +312,8 @@ final class BindingCodecContext implements CodecContextFactory, BindingCodecTree
                 throw new IllegalStateException("Unable to load codec for " + valueType, e);
             }
         } else if (typeDef instanceof LeafrefTypeDefinition) {
-            final Entry<GeneratedType, Object> typeWithSchema = context.getTypeWithSchema(valueType);
-            final Object schema = typeWithSchema.getValue();
+            final Entry<GeneratedType, WithStatus> typeWithSchema = context.getTypeWithSchema(valueType);
+            final WithStatus schema = typeWithSchema.getValue();
             Preconditions.checkState(schema instanceof TypeDefinition<?>);
             return getCodec(valueType, (TypeDefinition<?>) schema);
         }
index ebc168ccc45ceb6b500d78e587c9116ec5a50a86..aa03601f470ec28a9cf9be40b3e71d520802cbde 100644 (file)
@@ -17,36 +17,30 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
  * Transform Schema Context to Generated types.
  */
 public interface BindingGenerator {
-
     /**
-     * Generate Types from whole Schema Context. <br>
-     * The method will return List of All Generated Types that could be
+     * Generate Types from whole Schema Context. The method will return List of All Generated Types that could be
      * Generated from Schema Context.
      *
-     *
-     * @param context
-     *            Schema Context
+     * @param context Schema Context
      * @return List of Generated Types
      *
      * @see SchemaContext
      */
-    List<Type> generateTypes(final SchemaContext context);
+    default List<Type> generateTypes(final SchemaContext context) {
+        return generateTypes(context, context.getModules());
+    }
 
     /**
-     * Generate Types from Schema Context restricted by sub set of specified
-     * Modules. The Schema Context MUST contain all of the sub modules otherwise
-     * the there is no guarantee that result List of Generated Types will
-     * contain correct Generated Types.
+     * Generate Types from Schema Context restricted by sub set of specified Modules. The Schema Context MUST contain
+     * all of the sub modules otherwise the there is no guarantee that result List of Generated Types will contain
+     * correct Generated Types.
      *
-     * @param context
-     *            Schema Context
-     * @param modules
-     *            Sub Set of Modules
+     * @param context Schema Context
+     * @param modules Sub Set of Modules
      * @return List of Generated Types restricted by sub set of Modules
      *
      * @see Module
      * @see SchemaContext
-     *
      */
-    List<Type> generateTypes(final SchemaContext context, final Set<Module> modules);
+    List<Type> generateTypes(SchemaContext context, Set<Module> modules);
 }
diff --git a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeGenerator.java b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeGenerator.java
new file mode 100644 (file)
index 0000000..e592f90
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.api;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * Runtime equivalent of {@link BindingGenerator}. It generates equivalent type information, but does not include
+ * metadata not required at runtime, such as comments, references and similar.
+ */
+@Beta
+public interface BindingRuntimeGenerator {
+    /**
+     * Generate Type mapping from specified {@link SchemaContext} for the specified subset of modules. The SchemaContext
+     * MUST contain all of the sub modules otherwise the there is no guarantee that result List of Generated Types will
+     * contain correct Generated Types.
+     *
+     * @param context Schema Context
+     * @return Generated type mapping.
+     */
+    BindingRuntimeTypes generateTypeMapping(SchemaContext context);
+}
diff --git a/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeTypes.java b/binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/generator/api/BindingRuntimeTypes.java
new file mode 100644 (file)
index 0000000..007992b
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
+
+/**
+ * The result of BindingGenerator run. Contains mapping between Types and SchemaNodes.
+ */
+@Beta
+@ThreadSafe
+public final class BindingRuntimeTypes implements Immutable {
+    private final Map<Type, AugmentationSchemaNode> typeToAugmentation;
+    private final BiMap<Type, WithStatus> typeToSchema;
+    private final Multimap<Type, Type> choiceToCases;
+    private final Map<QName, Type> identities;
+
+    public BindingRuntimeTypes(final Map<Type, AugmentationSchemaNode> typeToAugmentation,
+            final BiMap<Type, WithStatus> typeToDefiningSchema, final Multimap<Type, Type> choiceToCases,
+            final Map<QName, Type> identities) {
+        this.typeToAugmentation = ImmutableMap.copyOf(typeToAugmentation);
+        this.typeToSchema = ImmutableBiMap.copyOf(typeToDefiningSchema);
+        this.choiceToCases = ImmutableMultimap.copyOf(choiceToCases);
+        this.identities = ImmutableMap.copyOf(identities);
+    }
+
+    public Optional<AugmentationSchemaNode> findAugmentation(final Type type) {
+        return Optional.ofNullable(typeToAugmentation.get(type));
+    }
+
+    public Optional<Type> findIdentity(final QName qname) {
+        return Optional.ofNullable(identities.get(qname));
+    }
+
+    public Optional<WithStatus> findSchema(final Type type) {
+        return Optional.ofNullable(typeToSchema.get(type));
+    }
+
+    public Optional<Type> findType(final WithStatus schema) {
+        return Optional.ofNullable(typeToSchema.inverse().get(schema));
+    }
+
+    public Multimap<Type, Type> getChoiceToCases() {
+        return choiceToCases;
+    }
+
+    public Collection<Type> findCases(final Type choiceType) {
+        return choiceToCases.get(choiceType);
+    }
+}
index 24f11cef0fde3808684b7502a49ee9cc0c06ba46..daa5e6fb15965f8bff2058877983963efe87b2f4 100644 (file)
@@ -34,15 +34,12 @@ public interface TypeProvider {
      * @param type Type Definition to resolve from
      * @return Resolved Type
      */
-    Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> type, final SchemaNode parentNode);
+    Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode);
 
-    Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> type, final SchemaNode parentNode, final Restrictions restrictions);
+    Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode, Restrictions restrictions);
 
     /**
      * Returns string containing code for creation of new type instance.
-     *
-     * @param node
-     * @return
      */
     String getTypeDefaultConstruction(LeafSchemaNode node);
 
diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
new file mode 100644 (file)
index 0000000..03f14d5
--- /dev/null
@@ -0,0 +1,2037 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.impl;
+
+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 java.util.Objects.requireNonNull;
+import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.computeDefaultSUID;
+import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.encodeAngleBrackets;
+import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForAugmentedGeneratedType;
+import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForGeneratedType;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_OBJECT;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_ROOT;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIABLE;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIER;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.augmentable;
+import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN;
+import static org.opendaylight.mdsal.binding.model.util.Types.FUTURE;
+import static org.opendaylight.mdsal.binding.model.util.Types.VOID;
+import static org.opendaylight.mdsal.binding.model.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.findParentModule;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import org.opendaylight.mdsal.binding.model.api.AccessModifier;
+import org.opendaylight.mdsal.binding.model.api.Constant;
+import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding.model.api.Restrictions;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotationTypeBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.EnumBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
+import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
+import org.opendaylight.mdsal.binding.model.util.BindingTypes;
+import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl;
+import org.opendaylight.mdsal.binding.model.util.Types;
+import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedPropertyBuilderImpl;
+import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedTOBuilderImpl;
+import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedTypeBuilderImpl;
+import org.opendaylight.mdsal.binding.yang.types.GroupingDefinitionDependencySort;
+import org.opendaylight.mdsal.binding.yang.types.TypeProviderImpl;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+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.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleImport;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
+import org.opendaylight.yangtools.yang.model.util.ModuleDependencySort;
+import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
+import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
+import org.opendaylight.yangtools.yang.model.util.type.CompatUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractTypeGenerator {
+    private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+
+    /**
+     * Comparator based on augment target path.
+     */
+    private static final Comparator<AugmentationSchemaNode> AUGMENT_COMP = (o1, o2) -> {
+        final Iterator<QName> thisIt = o1.getTargetPath().getPathFromRoot().iterator();
+        final Iterator<QName> otherIt = o2.getTargetPath().getPathFromRoot().iterator();
+
+        while (thisIt.hasNext()) {
+            if (!otherIt.hasNext()) {
+                return 1;
+            }
+
+            final int comp = thisIt.next().compareTo(otherIt.next());
+            if (comp != 0) {
+                return comp;
+            }
+        }
+
+        return otherIt.hasNext() ? -1 : 0;
+    };
+
+    /**
+     * 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<>();
+
+    /**
+     * Outer key represents the package name. Outer value represents map of all
+     * builders in the same package. Inner key represents the schema node name
+     * (in JAVA class/interface name format). Inner value represents instance of
+     * builder for schema node specified in key part.
+     */
+    private final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders = new HashMap<>();
+
+    /**
+     * Provide methods for converting YANG types to JAVA types.
+     */
+    private final TypeProviderImpl typeProvider;
+
+    /**
+     * Holds reference to schema context to resolve data of augmented element
+     * when creating augmentation builder
+     */
+    private final SchemaContext schemaContext;
+
+    AbstractTypeGenerator(final SchemaContext context, final TypeProviderImpl typeProvider) {
+        this.schemaContext = requireNonNull(context);
+        this.typeProvider = requireNonNull(typeProvider);
+
+        final List<Module> contextModules = ModuleDependencySort.sort(schemaContext.getModules());
+        for (final Module contextModule : contextModules) {
+            moduleToGenTypes(contextModule, schemaContext);
+        }
+        for (final Module contextModule : contextModules) {
+            allAugmentsToGenTypes(contextModule);
+        }
+    }
+
+    final Collection<ModuleContext> moduleContexts() {
+        return genCtx.values();
+    }
+
+    final ModuleContext moduleContext(final Module module) {
+        return checkNotNull(genCtx.get(module), "Module context not found for module %s", module);
+    }
+
+    final TypeProviderImpl typeProvider() {
+        return typeProvider;
+    }
+
+    abstract void addCodegenInformation(GeneratedTypeBuilderBase<?> genType, Module module);
+
+    abstract void addCodegenInformation(GeneratedTypeBuilderBase<?> genType, Module module, SchemaNode node);
+
+    abstract void addCodegenInformation(GeneratedTypeBuilder interfaceBuilder, Module module, String description,
+            Set<? extends SchemaNode> nodes);
+
+    abstract void addComment(TypeMemberBuilder<?> genType, DocumentedNode node);
+
+    private void moduleToGenTypes(final Module m, final SchemaContext context) {
+        genCtx.put(m, new ModuleContext());
+        allTypeDefinitionsToGenTypes(m);
+        groupingsToGenTypes(m, m.getGroupings());
+        rpcMethodsToGenType(m);
+        allIdentitiesToGenTypes(m, context);
+        notificationsToGenType(m);
+
+        if (!m.getChildNodes().isEmpty()) {
+            final GeneratedTypeBuilder moduleType = moduleToDataType(m);
+            genCtx.get(m).addModuleNode(moduleType);
+            final String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
+            resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.getChildNodes());
+        }
+    }
+
+    /**
+     * Converts all extended type definitions of module to the list of
+     * <code>Type</code> objects.
+     *
+     * @param module
+     *            module from which is obtained set of type definitions
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if module is null</li>
+     *             <li>if name of module is null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if set of type definitions from module is null
+     */
+    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);
+        final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
+        checkState(typeDefinitions != null, "Type Definitions for module %s cannot be NULL.", module.getName());
+
+        for (final TypeDefinition<?> typedef : typeDefinitions) {
+            if (typedef != null) {
+                final Type type = typeProvider.generatedTypeForExtendedDefinitionType(typedef,
+                        typedef);
+                if (type != null) {
+                    final ModuleContext ctx = genCtx.get(module);
+                    ctx.addTypedefType(typedef.getPath(), type);
+                    ctx.addTypeToSchema(type,typedef);
+                }
+            }
+        }
+    }
+
+    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, module);
+        annotateDeprecatedIfNecessary(node.getStatus(), genType);
+
+        genType.setModuleName(module.getName());
+        addCodegenInformation(genType, module, node);
+        genType.setSchemaPath(node.getPath().getPathFromRoot());
+        if (node instanceof DataNodeContainer) {
+            genCtx.get(module).addChildNodeType(node, genType);
+            groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
+            processUsesAugments((DataNodeContainer) node, module);
+        }
+        return genType;
+    }
+
+    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, genType, node);
+            resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes());
+        }
+    }
+
+    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, Types.listTypeFor(genType), node);
+
+            final List<String> listKeys = listKeys(node);
+            final String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
+            final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
+            if (genTOBuilder != null) {
+                final Type identifierMarker = Types.parameterizedTypeFor(IDENTIFIER, genType);
+                final Type identifiableMarker = Types.parameterizedTypeFor(IDENTIFIABLE, genTOBuilder);
+                genTOBuilder.addImplementsType(identifierMarker);
+                genType.addImplementsType(identifiableMarker);
+            }
+
+            for (final DataSchemaNode schemaNode : node.getChildNodes()) {
+                if (!schemaNode.isAugmenting()) {
+                    addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module);
+                }
+            }
+
+            // serialVersionUID
+            if (genTOBuilder != null) {
+                final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
+                prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
+                genTOBuilder.setSUID(prop);
+            }
+
+            typeBuildersToGenTypes(module, genType, genTOBuilder);
+        }
+    }
+
+    private void processUsesAugments(final DataNodeContainer node, final Module module) {
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+        for (final UsesNode usesNode : node.getUses()) {
+            for (final AugmentationSchemaNode augment : usesNode.getAugmentations()) {
+                usesAugmentationToGenTypes(basePackageName, augment, module, usesNode, node);
+                processUsesAugments(augment, module);
+            }
+        }
+    }
+
+    /**
+     * Converts all <b>augmentation</b> of the module to the list
+     * <code>Type</code> objects.
+     *
+     * @param module
+     *            module from which is obtained list of all augmentation objects
+     *            to iterate over them
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if the module is null</li>
+     *             <li>if the name of module is null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if set of augmentations from module is null
+     */
+    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 = BindingMapping.getRootPackageName(module.getQNameModule());
+        for (final AugmentationSchemaNode augment : resolveAugmentations(module)) {
+            augmentationToGenTypes(basePackageName, augment, module);
+        }
+    }
+
+    /**
+     * Returns list of <code>AugmentationSchema</code> objects. The objects are
+     * sorted according to the length of their target path from the shortest to
+     * the longest.
+     *
+     * @param module
+     *            module from which is obtained list of all augmentation objects
+     * @return list of sorted <code>AugmentationSchema</code> objects obtained
+     *         from <code>module</code>
+     * @throws IllegalArgumentException
+     *             if module is null
+     * @throws IllegalStateException
+     *             if set of module augmentations is null
+     */
+    private static List<AugmentationSchemaNode> resolveAugmentations(final Module module) {
+        checkArgument(module != null, "Module reference cannot be NULL.");
+        checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
+
+        final Set<AugmentationSchemaNode> augmentations = module.getAugmentations();
+        final List<AugmentationSchemaNode> sortedAugmentations = new ArrayList<>(augmentations);
+        sortedAugmentations.sort(AUGMENT_COMP);
+
+        return sortedAugmentations;
+    }
+
+    /**
+     * Create GeneratedTypeBuilder object from module argument.
+     *
+     * @param module
+     *            Module object from which builder will be created
+     * @return <code>GeneratedTypeBuilder</code> which is internal
+     *         representation of the module
+     * @throws IllegalArgumentException
+     *             if module is null
+     */
+    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);
+
+        addCodegenInformation(moduleDataTypeBuilder, module);
+        return moduleDataTypeBuilder;
+    }
+
+    /**
+     * Converts all <b>RPCs</b> input and output substatements of the module
+     * to the list of <code>Type</code> objects. In addition are to containers
+     * and lists which belong to input or output also part of returning list.
+     *
+     * @param module
+     *            module from which is obtained set of all rpc objects to
+     *            iterate over them
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if the module is null</li>
+     *             <li>if the name of module is null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if set of rpcs from module is null
+     */
+    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();
+        checkState(rpcDefinitions != null, "Set of rpcs from module " + module.getName() + " cannot be NULL.");
+        if (rpcDefinitions.isEmpty()) {
+            return;
+        }
+
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+        final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
+        interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
+
+        addCodegenInformation(interfaceBuilder, module, "RPCs", rpcDefinitions);
+
+        for (final RpcDefinition rpc : rpcDefinitions) {
+            if (rpc != null) {
+                final String rpcName = BindingMapping.getClassName(rpc.getQName());
+                final String rpcMethodName = BindingMapping.getPropertyName(rpcName);
+                final MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
+                final ContainerSchemaNode input = rpc.getInput();
+                final ContainerSchemaNode output = rpc.getOutput();
+
+                // Do not refer to annotation class, as it may not be available at runtime
+                method.addAnnotation("javax.annotation", "CheckReturnValue");
+
+                //in case of implicit RPC input (StatementSource.CONTEXT),
+                // stay compatible (no input argument generated)
+                if (input != null && isExplicitStatement(input)) {
+                    processUsesAugments(input, module);
+                    final GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
+                    addImplementedInterfaceFromUses(input, inType);
+                    inType.addImplementsType(DATA_OBJECT);
+                    inType.addImplementsType(augmentable(inType));
+                    annotateDeprecatedIfNecessary(rpc.getStatus(), inType);
+                    resolveDataSchemaNodes(module, basePackageName, inType, inType, input.getChildNodes());
+                    genCtx.get(module).addChildNodeType(input, inType);
+                    final GeneratedType inTypeInstance = inType.toInstance();
+                    method.addParameter(inTypeInstance, "input");
+                }
+
+                Type outTypeInstance = VOID;
+                //in case of implicit RPC output (StatementSource.CONTEXT),
+                //stay compatible (Future<RpcResult<Void>> return type generated)
+                if (output != null && isExplicitStatement(output)) {
+                    processUsesAugments(output, module);
+                    final GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
+                    addImplementedInterfaceFromUses(output, outType);
+                    outType.addImplementsType(DATA_OBJECT);
+                    outType.addImplementsType(augmentable(outType));
+                    annotateDeprecatedIfNecessary(rpc.getStatus(), outType);
+                    resolveDataSchemaNodes(module, basePackageName, outType, outType, output.getChildNodes());
+                    genCtx.get(module).addChildNodeType(output, outType);
+                    outTypeInstance = outType.toInstance();
+                }
+
+                final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
+                addComment(method, rpc);
+                method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
+            }
+        }
+
+        genCtx.get(module).addTopLevelNodeType(interfaceBuilder);
+    }
+
+    private static boolean isExplicitStatement(final ContainerSchemaNode node) {
+        return node instanceof EffectiveStatement
+                && ((EffectiveStatement<?, ?>) node).getDeclared().getStatementSource() == StatementSource.DECLARATION;
+    }
+
+    /**
+     * Converts all <b>notifications</b> of the module to the list of
+     * <code>Type</code> objects. In addition are to this list added containers
+     * and lists which are part of this notification.
+     *
+     * @param module
+     *            module from which is obtained set of all notification objects
+     *            to iterate over them
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if the module equals null</li>
+     *             <li>if the name of module equals null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if set of notifications from module is null
+     */
+    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();
+        if (notifications.isEmpty()) {
+            return;
+        }
+
+        final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener");
+        listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+
+        for (final NotificationDefinition notification : notifications) {
+            if (notification != null) {
+                processUsesAugments(notification, module);
+
+                final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName,
+                        notification, null, module);
+                annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
+                notificationInterface.addImplementsType(NOTIFICATION);
+                genCtx.get(module).addChildNodeType(notification, notificationInterface);
+
+                // Notification object
+                resolveDataSchemaNodes(module, basePackageName, notificationInterface, notificationInterface,
+                        notification.getChildNodes());
+
+                addComment(listenerInterface.addMethod("on" + notificationInterface.getName())
+                    .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
+                    .setReturnType(Types.VOID), notification);
+            }
+        }
+
+        addCodegenInformation(listenerInterface, module, "notifications", notifications);
+        genCtx.get(module).addTopLevelNodeType(listenerInterface);
+    }
+
+    /**
+     * Converts all <b>identities</b> of the module to the list of
+     * <code>Type</code> objects.
+     *
+     * @param module
+     *            module from which is obtained set of all identity objects to
+     *            iterate over them
+     * @param context
+     *            schema context only used as input parameter for method
+     *            {@link BindingGeneratorImpl#identityToGenType}
+     *
+     */
+    private void allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
+        final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
+        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
+
+        if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
+            for (final IdentitySchemaNode identity : schemaIdentities) {
+                identityToGenType(module, basePackageName, identity, context);
+            }
+        }
+    }
+
+    /**
+     * Converts the <b>identity</b> object to GeneratedType. Firstly it is
+     * created transport object builder. If identity contains base identity then
+     * reference to base identity is added to superior identity as its extend.
+     * If identity doesn't contain base identity then only reference to abstract
+     * class {@link org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
+     * BaseIdentity} is added
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string contains the module package name
+     * @param identity
+     *            IdentitySchemaNode which contains data about identity
+     * @param context
+     *            SchemaContext which is used to get package and name
+     *            information about base of identity
+     *
+     */
+    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 GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
+        final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
+        if (baseIdentities.isEmpty()) {
+            final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
+                    BaseIdentity.class.getSimpleName());
+            newType.setExtendsType(gto.toInstance());
+        } else {
+            final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next();
+            final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
+            final String returnTypePkgName = BindingMapping.getRootPackageName(baseIdentityParentModule
+                    .getQNameModule());
+            final String returnTypeName = BindingMapping.getClassName(baseIdentity.getQName());
+            final GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName)
+            .toInstance();
+            newType.setExtendsType(gto);
+        }
+        newType.setAbstract(true);
+
+        addCodegenInformation(newType, module, identity);
+        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(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
+            final QName name) {
+        return toBuilder.addConstant(typeForClass(QName.class), constantName, name);
+    }
+
+    /**
+     * Converts all <b>groupings</b> of the module to the list of
+     * <code>Type</code> objects. Firstly are groupings sorted according mutual
+     * dependencies. At least dependent (independent) groupings are in the list
+     * saved at first positions. For every grouping the record is added to map
+     * {@link ModuleContext#groupings allGroupings}
+     *
+     * @param module
+     *            current module
+     * @param groupings
+     *            collection of groupings from which types will be generated
+     *
+     */
+    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);
+        for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
+            groupingToGenType(basePackageName, grouping, module);
+        }
+    }
+
+    /**
+     * Converts individual grouping to GeneratedType. Firstly generated type
+     * builder is created and every child node of grouping is resolved to the
+     * method.
+     *
+     * @param basePackageName
+     *            string contains the module package name
+     * @param grouping
+     *            GroupingDefinition which contains data about grouping
+     * @param module
+     *            current 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, module);
+        annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
+        genCtx.get(module).addGroupingType(grouping.getPath(), genType);
+        resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes());
+        groupingsToGenTypes(module, grouping.getGroupings());
+        processUsesAugments(grouping, module);
+    }
+
+    /**
+     * Adds enumeration builder created from <code>enumTypeDef</code> to
+     * <code>typeBuilder</code>.
+     *
+     * Each <code>enumTypeDef</code> item is added to builder with its name and
+     * value.
+     *
+     * @param enumTypeDef
+     *            EnumTypeDefinition contains enum data
+     * @param enumName
+     *            string contains name which will be assigned to enumeration
+     *            builder
+     * @param typeBuilder
+     *            GeneratedTypeBuilder to which will be enum builder assigned
+     * @param module
+     *            Module in which type should be generated
+     * @return enumeration builder which contains data from
+     *         <code>enumTypeDef</code>
+     */
+    private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName,
+            final GeneratedTypeBuilder typeBuilder, final Module module) {
+        if (enumTypeDef != null && typeBuilder != null && enumTypeDef.getQName().getLocalName() != null) {
+            final String enumerationName = BindingMapping.getClassName(enumName);
+            final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+            final String enumTypedefDescription = encodeAngleBrackets(enumTypeDef.getDescription().orElse(null));
+            enumBuilder.setDescription(enumTypedefDescription);
+            enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
+            ModuleContext ctx = genCtx.get(module);
+            ctx.addInnerTypedefType(enumTypeDef.getPath(), enumBuilder);
+            return enumBuilder;
+        }
+        return null;
+    }
+
+    /**
+     * Generates type builder for <code>module</code>.
+     *
+     * @param module
+     *            Module which is source of package name for generated type
+     *            builder
+     * @param postfix
+     *            string which is added to the module class name representation
+     *            as suffix
+     * @return instance of GeneratedTypeBuilder which represents
+     *         <code>module</code>.
+     * @throws IllegalArgumentException
+     *             if <code>module</code> is null
+     */
+    private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
+        checkArgument(module != null, "Module reference cannot be NULL.");
+        final String packageName = BindingMapping.getRootPackageName(module.getQNameModule());
+        final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
+
+        final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
+
+        moduleBuilder.setModuleName(moduleName);
+        addCodegenInformation(moduleBuilder, module);
+        return moduleBuilder;
+    }
+
+    /**
+     * Converts <code>augSchema</code> to list of <code>Type</code> which
+     * contains generated type for augmentation. In addition there are also
+     * generated types for all containers, list and choices which are child of
+     * <code>augSchema</code> node or a generated types for cases are added if
+     * augmented node is choice.
+     *
+     * @param augmentPackageName
+     *            string with the name of the package to which the augmentation
+     *            belongs
+     * @param augSchema
+     *            AugmentationSchema which is contains data about augmentation
+     *            (target path, childs...)
+     * @param module
+     *            current module
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>augmentPackageName</code> equals null</li>
+     *             <li>if <code>augSchema</code> equals null</li>
+     *             </ul>
+     * @throws IllegalStateException
+     *             if augment target path is null
+     */
+    private void augmentationToGenTypes(final String augmentPackageName, final AugmentationSchemaNode augSchema,
+            final Module module) {
+        checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
+        checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
+        checkState(augSchema.getTargetPath() != null,
+                "Augmentation Schema does not contain Target Path (Target Path is NULL).");
+
+        processUsesAugments(augSchema, module);
+        final SchemaPath targetPath = augSchema.getTargetPath();
+        SchemaNode targetSchemaNode = null;
+
+        targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
+        if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
+            if (targetSchemaNode instanceof DerivableSchemaNode) {
+                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orElse(null);
+            }
+            if (targetSchemaNode == null) {
+                throw new IllegalStateException("Failed to find target node from grouping in augmentation " + augSchema
+                        + " in module " + module.getName());
+            }
+        }
+        if (targetSchemaNode == null) {
+            throw new IllegalArgumentException("augment target not found: " + targetPath);
+        }
+
+        GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath());
+        if (targetTypeBuilder == null) {
+            targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath());
+        }
+        if (targetTypeBuilder == null) {
+            throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
+        }
+
+        if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
+            final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getPackageName(),
+                    targetTypeBuilder.getName());
+            addRawAugmentGenTypeDefinition(module, augmentPackageName, augmentPackageName, targetType, augSchema);
+
+        } else {
+            generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance(),
+                    (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), null);
+        }
+    }
+
+    private void usesAugmentationToGenTypes(final String augmentPackageName, final AugmentationSchemaNode 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,
+                "Augmentation Schema does not contain Target Path (Target Path is NULL).");
+
+        processUsesAugments(augSchema, module);
+        final SchemaPath targetPath = augSchema.getTargetPath();
+        final SchemaNode targetSchemaNode = findOriginalTargetFromGrouping(targetPath, usesNode);
+        if (targetSchemaNode == null) {
+            throw new IllegalArgumentException("augment target not found: " + targetPath);
+        }
+
+        GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath());
+        if (targetTypeBuilder == null) {
+            targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath());
+        }
+        if (targetTypeBuilder == null) {
+            throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
+        }
+
+        if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
+            String packageName = augmentPackageName;
+            if (usesNodeParent instanceof SchemaNode) {
+                packageName = packageNameForAugmentedGeneratedType(augmentPackageName,
+                    ((SchemaNode) usesNodeParent).getPath());
+            }
+            addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName, targetTypeBuilder.toInstance(),
+                    augSchema);
+        } else {
+            generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance(),
+                    (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), usesNodeParent);
+        }
+    }
+
+    /**
+     * Convenient method to find node added by uses statement.
+     *
+     * @param targetPath
+     *            node path
+     * @param parentUsesNode
+     *            parent of uses node
+     * @return node from its original location in grouping
+     */
+    private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) {
+        final SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.getGroupingPath()
+                .getPathFromRoot());
+        if (!(targetGrouping instanceof GroupingDefinition)) {
+            throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
+        }
+
+        SchemaNode result = targetGrouping;
+        for (final QName node : targetPath.getPathFromRoot()) {
+            if (result instanceof DataNodeContainer) {
+                final QName resultNode = QName.create(result.getQName().getModule(), node.getLocalName());
+                result = ((DataNodeContainer) result).getDataChildByName(resultNode);
+            } else if (result instanceof ChoiceSchemaNode) {
+                result = findNamedCase((ChoiceSchemaNode) result, node.getLocalName());
+            }
+        }
+        if (result == null) {
+            return null;
+        }
+
+        if (result instanceof DerivableSchemaNode) {
+            DerivableSchemaNode castedResult = (DerivableSchemaNode) result;
+            Optional<? extends SchemaNode> originalNode = castedResult.getOriginal();
+            if (castedResult.isAddedByUses() && originalNode.isPresent()) {
+                result = originalNode.get();
+            }
+        }
+
+        if (result instanceof DataSchemaNode) {
+            DataSchemaNode resultDataSchemaNode = (DataSchemaNode) result;
+            if (resultDataSchemaNode.isAddedByUses()) {
+                // The original node is required, but we have only the copy of
+                // the original node.
+                // Maybe this indicates a bug in Yang parser.
+                throw new IllegalStateException("Failed to generate code for augment in " + parentUsesNode);
+            }
+
+            return resultDataSchemaNode;
+        }
+
+        throw new IllegalStateException(
+            "Target node of uses-augment statement must be DataSchemaNode. Failed to generate code for augment in "
+                    + parentUsesNode);
+    }
+
+    /**
+     * Returns a generated type builder for an augmentation.
+     *
+     * The name of the type builder is equal to the name of augmented node with
+     * serial number as suffix.
+     *
+     * @param module
+     *            current module
+     * @param augmentPackageName
+     *            string with contains the package name to which the augment
+     *            belongs
+     * @param basePackageName
+     *            string with the package name to which the augmented node
+     *            belongs
+     * @param targetTypeRef
+     *            target type
+     * @param augSchema
+     *            augmentation schema which contains data about the child nodes
+     *            and uses of augment
+     * @return generated type builder for augment
+     */
+    private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
+            final String basePackageName, final Type targetTypeRef, final AugmentationSchemaNode augSchema) {
+        Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
+        if (augmentBuilders == null) {
+            augmentBuilders = new HashMap<>();
+            genTypeBuilders.put(augmentPackageName, augmentBuilders);
+        }
+        final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
+
+        String augTypeName;
+        if (augIdentifier != null) {
+            augTypeName = BindingMapping.getClassName(augIdentifier);
+        } else {
+            augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName());
+        }
+
+        final GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
+
+        augTypeBuilder.addImplementsType(DATA_OBJECT);
+        augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
+        annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
+        addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
+
+        augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.getChildNodes());
+        augmentBuilders.put(augTypeName, augTypeBuilder);
+
+        if (!augSchema.getChildNodes().isEmpty()) {
+            genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
+
+        }
+        genCtx.get(module).addAugmentType(augTypeBuilder);
+        return augTypeBuilder;
+    }
+
+    /**
+     *
+     * @param unknownSchemaNodes
+     * @return nodeParameter of UnknownSchemaNode
+     */
+    private static String getAugmentIdentifier(final List<UnknownSchemaNode> unknownSchemaNodes) {
+        for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
+            final QName nodeType = unknownSchemaNode.getNodeType();
+            if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName())
+                    && YANG_EXT_NAMESPACE.equals(nodeType.getNamespace().toString())) {
+                return unknownSchemaNode.getNodeParameter();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns first unique name for the augment generated type builder. The
+     * generated type builder name for augment consists from name of augmented
+     * node and serial number of its augmentation.
+     *
+     * @param builders
+     *            map of builders which were created in the package to which the
+     *            augmentation belongs
+     * @param genTypeName
+     *            string with name of augmented node
+     * @return string with unique name for augmentation builder
+     */
+    private static String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
+        int index = 1;
+        if (builders != null) {
+            while (builders.containsKey(genTypeName + index)) {
+                index = index + 1;
+            }
+        }
+        return genTypeName + index;
+    }
+
+    /**
+     * Adds the methods to <code>typeBuilder</code> which represent subnodes of
+     * node for which <code>typeBuilder</code> was created.
+     *
+     * The subnodes aren't mapped to the methods if they are part of grouping or
+     * augment (in this case are already part of them).
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string contains the module package name
+     * @param parent
+     *            generated type builder which represents any node. The subnodes
+     *            of this node are added to the <code>typeBuilder</code> as
+     *            methods. The subnode can be of type leaf, leaf-list, list,
+     *            container, choice.
+     * @param childOf
+     *            parent type
+     * @param schemaNodes
+     *            set of data schema nodes which are the children of the node
+     *            for which <code>typeBuilder</code> was created
+     * @return generated type builder which is the same builder as input
+     *         parameter. The getter methods (representing child nodes) could be
+     *         added to it.
+     */
+    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 (final DataSchemaNode schemaNode : schemaNodes) {
+                if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
+                    addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
+                }
+            }
+        }
+        return parent;
+    }
+
+    /**
+     * Adds the methods to <code>typeBuilder</code> what represents subnodes of
+     * node for which <code>typeBuilder</code> was created.
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string contains the module package name
+     * @param typeBuilder
+     *            generated type builder which represents any node. The subnodes
+     *            of this node are added to the <code>typeBuilder</code> as
+     *            methods. The subnode can be of type leaf, leaf-list, list,
+     *            container, choice.
+     * @param childOf
+     *            parent type
+     * @param schemaNodes
+     *            set of data schema nodes which are the children of the node
+     *            for which <code>typeBuilder</code> was created
+     * @return generated type builder which is the same object as the input
+     *         parameter <code>typeBuilder</code>. The getter method could be
+     *         added to it.
+     */
+    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 (final DataSchemaNode schemaNode : schemaNodes) {
+                if (!schemaNode.isAugmenting()) {
+                    addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
+                }
+            }
+        }
+        return typeBuilder;
+    }
+
+    /**
+     * Adds to <code>typeBuilder</code> a method which is derived from
+     * <code>schemaNode</code>.
+     *
+     * @param basePackageName
+     *            string with the module package name
+     * @param node
+     *            data schema node which is added to <code>typeBuilder</code> as
+     *            a method
+     * @param typeBuilder
+     *            generated type builder to which is <code>schemaNode</code>
+     *            added as a method.
+     * @param childOf
+     *            parent type
+     * @param module
+     *            current 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, module);
+            } else if (node instanceof LeafListSchemaNode) {
+                resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) node,module);
+            } else if (node instanceof ContainerSchemaNode) {
+                containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node);
+            } else if (node instanceof ListSchemaNode) {
+                listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node);
+            } else if (node instanceof ChoiceSchemaNode) {
+                choiceToGeneratedType(module, basePackageName, typeBuilder, (ChoiceSchemaNode) node);
+            } else {
+                // TODO: anyxml not yet supported
+                LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(),
+                        typeBuilder.getFullyQualifiedName());
+            }
+        }
+    }
+
+    /**
+     * Converts <code>choiceNode</code> to the list of generated types for
+     * choice and its cases.
+     *
+     * The package names for choice and for its cases are created as
+     * concatenation of the module package (<code>basePackageName</code>) and
+     * names of all parents node.
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string with the module package name
+     * @param parent
+     *            parent type
+     * @param choiceNode
+     *            choice node which is mapped to generated type. Also child
+     *            nodes - cases are mapped to generated types.
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>basePackageName</code> is null</li>
+     *             <li>if <code>choiceNode</code> is null</li>
+     *             </ul>
+     */
+    private void choiceToGeneratedType(final Module module, final String basePackageName,
+            final GeneratedTypeBuilder parent, final ChoiceSchemaNode choiceNode) {
+        checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
+        checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
+
+        if (!choiceNode.isAddedByUses()) {
+            final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
+            final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
+            constructGetter(parent, choiceTypeBuilder, choiceNode);
+            choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
+            annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
+            genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
+            generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
+        }
+    }
+
+    /**
+     * Converts <code>caseNodes</code> set to list of corresponding generated
+     * types.
+     *
+     * For every <i>case</i> which isn't added through augment or <i>uses</i> is
+     * created generated type builder. The package names for the builder is
+     * created as concatenation of the module package (
+     * <code>basePackageName</code>) and names of all parents nodes of the
+     * concrete <i>case</i>. There is also relation "<i>implements type</i>"
+     * between every case builder and <i>choice</i> type
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string with the module package name
+     * @param refChoiceType
+     *            type which represents superior <i>case</i>
+     * @param choiceNode
+     *            choice case node which is mapped to generated type
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>basePackageName</code> equals null</li>
+     *             <li>if <code>refChoiceType</code> equals null</li>
+     *             <li>if <code>caseNodes</code> equals null</li>
+     *             </ul>
+     */
+    private void generateTypesFromChoiceCases(final Module module, final String basePackageName,
+            final Type refChoiceType, final ChoiceSchemaNode 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.");
+
+        for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) {
+            if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
+                final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode,
+                    module);
+                caseTypeBuilder.addImplementsType(refChoiceType);
+                annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder);
+                genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
+                genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
+                final Iterable<DataSchemaNode> caseChildNodes = caseNode.getChildNodes();
+                if (caseChildNodes != null) {
+                    final SchemaPath choiceNodeParentPath = choiceNode.getPath().getParent();
+
+                    if (!Iterables.isEmpty(choiceNodeParentPath.getPathFromRoot())) {
+                        SchemaNode parent = findDataSchemaNode(schemaContext, choiceNodeParentPath);
+
+                        if (parent instanceof AugmentationSchemaNode) {
+                            final AugmentationSchemaNode augSchema = (AugmentationSchemaNode) parent;
+                            final SchemaPath targetPath = augSchema.getTargetPath();
+                            SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
+                            if (targetSchemaNode instanceof DataSchemaNode
+                                    && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
+                                if (targetSchemaNode instanceof DerivableSchemaNode) {
+                                    targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal()
+                                            .orElse(null);
+                                }
+                                if (targetSchemaNode == null) {
+                                    throw new IllegalStateException(
+                                            "Failed to find target node from grouping for augmentation " + augSchema
+                                                    + " in module " + module.getName());
+                                }
+                            }
+                            parent = targetSchemaNode;
+                        }
+
+                        checkState(parent != null, "Could not find Choice node parent %s", choiceNodeParentPath);
+                        GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
+                        if (childOfType == null) {
+                            childOfType = findGroupingByPath(parent.getPath());
+                        }
+                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
+                    } else {
+                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, moduleToDataType(module),
+                                caseChildNodes);
+                    }
+               }
+            }
+            processUsesAugments(caseNode, module);
+        }
+    }
+
+    /**
+     * Generates list of generated types for all the cases of a choice which are
+     * added to the choice through the augment.
+     *
+     * @param module
+     *            current module
+     * @param basePackageName
+     *            string contains name of package to which augment belongs. If
+     *            an augmented choice is from an other package (pcg1) than an
+     *            augmenting choice (pcg2) then case's of the augmenting choice
+     *            will belong to pcg2.
+     * @param targetType
+     *            Type which represents target choice
+     * @param targetNode
+     *            node which represents target choice
+     * @param augmentedNodes
+     *            set of choice case nodes for which is checked if are/aren't
+     *            added to choice through augmentation
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>basePackageName</code> is null</li>
+     *             <li>if <code>targetType</code> is null</li>
+     *             <li>if <code>augmentedNodes</code> is null</li>
+     *             </ul>
+     */
+    private void generateTypesFromAugmentedChoiceCases(final Module module, final String basePackageName,
+            final Type targetType, final ChoiceSchemaNode targetNode, final Iterable<DataSchemaNode> augmentedNodes,
+            final DataNodeContainer usesNodeParent) {
+        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.");
+
+        for (final DataSchemaNode caseNode : augmentedNodes) {
+            if (caseNode != null) {
+                final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
+                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
+                caseTypeBuilder.addImplementsType(targetType);
+
+                SchemaNode parent;
+                final SchemaPath nodeSp = targetNode.getPath();
+                parent = findDataSchemaNode(schemaContext, nodeSp.getParent());
+
+                GeneratedTypeBuilder childOfType = null;
+                if (parent instanceof Module) {
+                    childOfType = genCtx.get(parent).getModuleNode();
+                } else if (parent instanceof CaseSchemaNode) {
+                    childOfType = findCaseByPath(parent.getPath());
+                } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
+                    childOfType = findChildNodeByPath(parent.getPath());
+                } else if (parent instanceof GroupingDefinition) {
+                    childOfType = findGroupingByPath(parent.getPath());
+                }
+
+                if (childOfType == null) {
+                    throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
+                }
+
+                CaseSchemaNode node = null;
+                final String caseLocalName = caseNode.getQName().getLocalName();
+                if (caseNode instanceof CaseSchemaNode) {
+                    node = (CaseSchemaNode) caseNode;
+                } else if (findNamedCase(targetNode, caseLocalName) == null) {
+                    final String targetNodeLocalName = targetNode.getQName().getLocalName();
+                    for (DataSchemaNode dataSchemaNode : usesNodeParent.getChildNodes()) {
+                        if (dataSchemaNode instanceof ChoiceSchemaNode && targetNodeLocalName.equals(dataSchemaNode.getQName
+                                ().getLocalName())) {
+                            node = findNamedCase((ChoiceSchemaNode) dataSchemaNode, caseLocalName);
+                            break;
+                        }
+                    }
+                } else {
+                    node = findNamedCase(targetNode, caseLocalName);
+                }
+                final Iterable<DataSchemaNode> childNodes = node.getChildNodes();
+                if (childNodes != null) {
+                    resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
+                }
+                genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
+                genCtx.get(module).addChoiceToCaseMapping(targetType, caseTypeBuilder, node);
+            }
+        }
+    }
+
+    private static CaseSchemaNode findNamedCase(final ChoiceSchemaNode choice, final String caseName) {
+        final List<CaseSchemaNode> cases = choice.findCaseNodes(caseName);
+        return cases.isEmpty() ? null : cases.get(0);
+    }
+
+    private static boolean isInnerType(final LeafSchemaNode leaf, final TypeDefinition<?> type) {
+        // New parser with encapsulated type
+        if (leaf.getPath().equals(type.getPath())) {
+            return true;
+        }
+
+        // Embedded type definition with new parser. Also takes care of the old parser with bits
+        if (leaf.getPath().equals(type.getPath().getParent())) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Converts <code>leaf</code> to the getter method which is added to
+     * <code>typeBuilder</code>.
+     *
+     * @param typeBuilder
+     *            generated type builder to which is added getter method as
+     *            <code>leaf</code> mapping
+     * @param leaf
+     *            leaf schema node which is mapped as getter method which is
+     *            added to <code>typeBuilder</code>
+     * @param module
+     *            Module in which type was defined
+     * @return boolean value
+     *         <ul>
+     *         <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
+     *         null</li>
+     *         <li>true - in other cases</li>
+     *         </ul>
+     */
+    private Type resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf, final Module module) {
+        if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
+            return null;
+        }
+
+        final Module parentModule = findParentModule(schemaContext, leaf);
+        Type returnType = null;
+
+        final TypeDefinition<?> typeDef = CompatUtils.compatLeafType(leaf);
+        if (isInnerType(leaf, typeDef)) {
+            if (typeDef instanceof EnumTypeDefinition) {
+                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
+                final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
+                final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
+                    typeBuilder, module);
+                if (enumBuilder != null) {
+                    returnType = enumBuilder.toInstance(typeBuilder);
+                }
+                typeProvider.putReferencedType(leaf.getPath(), returnType);
+            } else if (typeDef instanceof UnionTypeDefinition) {
+                GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
+                if (genTOBuilder != null) {
+                    returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
+                    // Store the inner type within the union so that we can find the reference for it
+                    genCtx.get(module).addInnerTypedefType(typeDef.getPath(), returnType);
+                }
+            } else if (typeDef instanceof BitsTypeDefinition) {
+                GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
+                if (genTOBuilder != null) {
+                    returnType = genTOBuilder.toInstance();
+                }
+            } else {
+                // It is constrained version of already declared type (inner declared type exists,
+                // onlyfor special cases (Enum, Union, Bits), which were already checked.
+                // In order to get proper class we need to look up closest derived type
+                // and apply restrictions from leaf type
+                final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
+                returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
+                        restrictions);
+            }
+        } else {
+            final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
+            returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
+        }
+
+        if (returnType == null) {
+            return null;
+        }
+
+        if (typeDef instanceof EnumTypeDefinition) {
+            typeProvider.putReferencedType(leaf.getPath(), returnType);
+        }
+
+        final MethodSignatureBuilder getter = constructGetter(typeBuilder,  returnType, leaf);
+        processContextRefExtension(leaf, getter, parentModule);
+        return returnType;
+    }
+
+    private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
+        // Returns DerivedType in case of new parser.
+        final TypeDefinition<?> baseType = typeDef.getBaseType();
+        return baseType != null && baseType.getBaseType() != null ? baseType : typeDef;
+    }
+
+    private void processContextRefExtension(final LeafSchemaNode leaf, final MethodSignatureBuilder getter,
+            final Module module) {
+        for (final 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 = 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 = BindingMapping.getRootPackageName(module.getQNameModule());
+                } else if (length == 2) {
+                    final String prefix = iterator.next();
+                    final Module dependentModule = findModuleFromImports(module.getImports(), prefix);
+                    if (dependentModule == null) {
+                        throw new IllegalArgumentException("Failed to process context-reference: unknown prefix "
+                                + prefix);
+                    }
+                    identity = findIdentityByName(dependentModule.getIdentities(), iterator.next());
+                    basePackageName = BindingMapping.getRootPackageName(dependentModule.getQNameModule());
+                } else {
+                    throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
+                            + nodeParam);
+                }
+                if (identity == null) {
+                    throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
+                            + nodeParam);
+                }
+
+                final Class<RoutingContext> clazz = RoutingContext.class;
+                final AnnotationTypeBuilder rc = getter.addAnnotation(clazz.getPackage().getName(),
+                        clazz.getSimpleName());
+                final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
+                final String genTypeName = BindingMapping.getClassName(identity.getQName().getLocalName());
+                rc.addParameter("value", packageName + "." + genTypeName + ".class");
+            }
+        }
+    }
+
+    private static IdentitySchemaNode findIdentityByName(final Set<IdentitySchemaNode> identities, final String name) {
+        for (final IdentitySchemaNode id : identities) {
+            if (id.getQName().getLocalName().equals(name)) {
+                return id;
+            }
+        }
+        return null;
+    }
+
+    private Module findModuleFromImports(final Set<ModuleImport> imports, final String prefix) {
+        for (final ModuleImport imp : imports) {
+            if (imp.getPrefix().equals(prefix)) {
+                return schemaContext.findModule(imp.getModuleName(), imp.getRevision()).orElse(null);
+            }
+        }
+        return null;
+    }
+
+    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
+            final boolean isReadOnly, final Module module) {
+        if (leaf != null && toBuilder != null) {
+            Type returnType;
+            final TypeDefinition<?> typeDef = CompatUtils.compatLeafType(leaf);
+            if (typeDef instanceof UnionTypeDefinition) {
+                // GeneratedType for this type definition should have be already created
+                final QName qname = typeDef.getQName();
+                final Module unionModule = schemaContext.findModule(qname.getModule()).orElse(null);
+                final ModuleContext mc = genCtx.get(unionModule);
+                returnType = mc.getTypedefs().get(typeDef.getPath());
+                if (returnType == null) {
+                    // This may still be an inner type, try to find it
+                    returnType = mc.getInnerType(typeDef.getPath());
+                }
+            } else if (typeDef instanceof EnumTypeDefinition && typeDef.getBaseType() == null) {
+                // Annonymous enumeration (already generated, since it is inherited via uses).
+                LeafSchemaNode originalLeaf = (LeafSchemaNode) SchemaNodeUtils.getRootOriginalIfPossible(leaf);
+                QName qname = originalLeaf.getQName();
+                final Module enumModule =  schemaContext.findModule(qname.getModule()).orElse(null);
+                returnType = genCtx.get(enumModule).getInnerType(originalLeaf.getType().getPath());
+            } else {
+                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
+            }
+            return resolveLeafSchemaNodeAsProperty(toBuilder, leaf, returnType, isReadOnly);
+        }
+        return false;
+    }
+
+    /**
+     * Converts <code>leaf</code> schema node to property of generated TO
+     * builder.
+     *
+     * @param toBuilder
+     *            generated TO builder to which is <code>leaf</code> added as
+     *            property
+     * @param leaf
+     *            leaf schema node which is added to <code>toBuilder</code> as
+     *            property
+     * @param returnType
+     *            property type
+     * @param isReadOnly
+     *            boolean value which says if leaf property is|isn't read only
+     * @return boolean value
+     *         <ul>
+     *         <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
+     *         name equals null or if leaf is added by <i>uses</i>.</li>
+     *         <li>true - other cases</li>
+     *         </ul>
+     */
+    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
+            final Type returnType, final boolean isReadOnly) {
+        if (returnType == null) {
+            return false;
+        }
+        final String leafName = leaf.getQName().getLocalName();
+        final GeneratedPropertyBuilder propBuilder = toBuilder.addProperty(BindingMapping.getPropertyName(leafName));
+        propBuilder.setReadOnly(isReadOnly);
+        propBuilder.setReturnType(returnType);
+        addComment(propBuilder, leaf);
+
+        toBuilder.addEqualsIdentity(propBuilder);
+        toBuilder.addHashIdentity(propBuilder);
+        toBuilder.addToStringProperty(propBuilder);
+        return true;
+    }
+
+    /**
+     * Converts <code>node</code> leaf list schema node to getter method of
+     * <code>typeBuilder</code>.
+     *
+     * @param typeBuilder
+     *            generated type builder to which is <code>node</code> added as
+     *            getter method
+     * @param node
+     *            leaf list schema node which is added to
+     *            <code>typeBuilder</code> as getter method
+     * @param module module
+     * @return boolean value
+     *         <ul>
+     *         <li>true - if <code>node</code>, <code>typeBuilder</code>,
+     *         nodeName equal null or <code>node</code> is added by <i>uses</i></li>
+     *         <li>false - other cases</li>
+     *         </ul>
+     */
+    private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node,
+            final Module module) {
+        if (node == null || typeBuilder == null || node.isAddedByUses()) {
+            return false;
+        }
+
+        final QName nodeName = node.getQName();
+
+        final TypeDefinition<?> typeDef = node.getType();
+        final Module parentModule = findParentModule(schemaContext, node);
+
+        Type returnType = null;
+        if (typeDef.getBaseType() == null) {
+            if (typeDef instanceof EnumTypeDefinition) {
+                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node);
+                final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
+                final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName,
+                    typeBuilder, module);
+                returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
+                typeProvider.putReferencedType(node.getPath(), returnType);
+            } else if (typeDef instanceof UnionTypeDefinition) {
+                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, parentModule);
+                returnType = genTOBuilder.toInstance();
+            } else {
+                final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
+                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);
+            }
+        } else {
+            final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
+            returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);
+        }
+
+        final ParameterizedType listType = Types.listTypeFor(returnType);
+        constructGetter(typeBuilder, listType, node);
+        return true;
+    }
+
+    private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final TypeDefinition<?> typeDef,
+            final GeneratedTypeBuilder typeBuilder, final Module parentModule) {
+        final GeneratedTOBuilderImpl returnType = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
+                genTOBuilder.getName());
+
+        addCodegenInformation(returnType, parentModule, typeDef);
+        returnType.setSchemaPath(typeDef.getPath().getPathFromRoot());
+        returnType.setModuleName(parentModule.getName());
+
+        genTOBuilder.setTypedef(true);
+        genTOBuilder.setIsUnion(true);
+        TypeProviderImpl.addUnitsToGenTO(genTOBuilder, typeDef.getUnits().orElse(null));
+
+
+
+        final GeneratedTOBuilder unionBuilder = createUnionBuilder(genTOBuilder,typeBuilder);
+
+
+        final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
+        method.setReturnType(returnType);
+        method.addParameter(Types.STRING, "defaultValue");
+        method.setAccessModifier(AccessModifier.PUBLIC);
+        method.setStatic(true);
+
+        final Set<Type> types = typeProvider.getAdditionalTypes().get(parentModule);
+        if (types == null) {
+            typeProvider.getAdditionalTypes().put(parentModule,
+                    Sets.newHashSet(unionBuilder.toInstance()));
+        } else {
+            types.add(unionBuilder.toInstance());
+        }
+        return returnType.toInstance();
+    }
+
+    private static GeneratedTOBuilder createUnionBuilder(final GeneratedTOBuilder genTOBuilder, final GeneratedTypeBuilder typeBuilder) {
+        final String outerCls = Types.getOuterClassName(genTOBuilder);
+        final StringBuilder name;
+        if (outerCls != null) {
+            name = new StringBuilder(outerCls);
+        } else {
+            name = new StringBuilder();
+        }
+        name.append(genTOBuilder.getName());
+        name.append("Builder");
+        final GeneratedTOBuilderImpl unionBuilder = new GeneratedTOBuilderImpl(typeBuilder.getPackageName(),name.toString());
+        unionBuilder.setIsUnionBuilder(true);
+        return unionBuilder;
+    }
+
+    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
+            final Module module) {
+        return addDefaultInterfaceDefinition(packageName, schemaNode, null, module);
+    }
+
+    /**
+     * Instantiates generated type builder with <code>packageName</code> and
+     * <code>schemaNode</code>.
+     *
+     * The new builder always implements
+     * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br>
+     * If <code>schemaNode</code> is instance of GroupingDefinition it also
+     * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
+     * Augmentable}.<br>
+     * If <code>schemaNode</code> is instance of
+     * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
+     * DataNodeContainer} it can also implement nodes which are specified in
+     * <i>uses</i>.
+     *
+     * @param packageName
+     *            string with the name of the package to which
+     *            <code>schemaNode</code> belongs.
+     * @param schemaNode
+     *            schema node for which is created generated type builder
+     * @param parent
+     *            parent type (can be null)
+     * @return generated type builder <code>schemaNode</code>
+     */
+    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);
+        } else {
+            it.addImplementsType(BindingTypes.childOf(parent));
+        }
+        if (!(schemaNode instanceof GroupingDefinition)) {
+            it.addImplementsType(augmentable(it));
+        }
+
+        if (schemaNode instanceof DataNodeContainer) {
+            groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
+            addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
+        }
+
+        return it;
+    }
+
+    /**
+     * Wraps the calling of the same overloaded method.
+     *
+     * @param packageName
+     *            string with the package name to which returning generated type
+     *            builder belongs
+     * @param schemaNode
+     *            schema node which provide data about the schema node name
+     * @return generated type builder for <code>schemaNode</code>
+     */
+    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
+        return addRawInterfaceDefinition(packageName, schemaNode, "");
+    }
+
+    /**
+     * Returns reference to generated type builder for specified
+     * <code>schemaNode</code> with <code>packageName</code>.
+     *
+     * Firstly the generated type builder is searched in
+     * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
+     * found it is created and added to <code>genTypeBuilders</code>.
+     *
+     * @param packageName
+     *            string with the package name to which returning generated type
+     *            builder belongs
+     * @param schemaNode
+     *            schema node which provide data about the schema node name
+     * @param prefix
+     *            return type name prefix
+     * @return generated type builder for <code>schemaNode</code>
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>schemaNode</code> is null</li>
+     *             <li>if <code>packageName</code> is null</li>
+     *             <li>if QName of schema node is null</li>
+     *             <li>if schemaNode name is null</li>
+     *             </ul>
+     *
+     */
+    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.");
+        final String schemaNodeName = schemaNode.getQName().getLocalName();
+        checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
+
+        String genTypeName;
+        if (prefix == null) {
+            genTypeName = BindingMapping.getClassName(schemaNodeName);
+        } else {
+            genTypeName = prefix + BindingMapping.getClassName(schemaNodeName);
+        }
+
+        // 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());
+
+        addCodegenInformation(newType, module, schemaNode);
+        newType.setSchemaPath(schemaNode.getPath().getPathFromRoot());
+        newType.setModuleName(module.getName());
+
+        if (!genTypeBuilders.containsKey(packageName)) {
+            final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
+            builders.put(genTypeName, newType);
+            genTypeBuilders.put(packageName, builders);
+        } else {
+            final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
+            if (!builders.containsKey(genTypeName)) {
+                builders.put(genTypeName, newType);
+            }
+        }
+        return newType;
+    }
+
+    /**
+     * Creates the name of the getter method name from <code>localName</code>.
+     *
+     * @param localName
+     *            string with the name of the getter method
+     * @param returnType
+     *            return type
+     * @return string with the name of the getter method for
+     *         <code>methodName</code> in JAVA method format
+     */
+    public static String getterMethodName(final String localName, final Type returnType) {
+        final StringBuilder method = new StringBuilder();
+        if (BOOLEAN.equals(returnType)) {
+            method.append("is");
+        } else {
+            method.append("get");
+        }
+        final String name = BindingMapping.toFirstUpper(BindingMapping.getPropertyName(localName));
+        method.append(name);
+        return method.toString();
+    }
+
+    /**
+     * Created a method signature builder as part of <code>interfaceBuilder</code>.
+     *
+     * The method signature builder is created for the getter method of <code>schemaNodeName</code>.
+     * Also <code>comment</code> and <code>returnType</code> information are added to the builder.
+     *
+     * @param interfaceBuilder generated type builder for which the getter method should be created
+     * @param returnType type which represents the return type of the getter method
+     * @param schemaNodeName string with schema node name. The name will be the part of the getter method name.
+     * @param comment string with comment for the getter method
+     * @param status status from yang file, for deprecated annotation
+     * @return method signature builder which represents the getter method of <code>interfaceBuilder</code>
+     */
+    private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder, final Type returnType,
+            final SchemaNode node) {
+        final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod(
+            getterMethodName(node.getQName().getLocalName(), returnType));
+        getMethod.setReturnType(returnType);
+
+        if (node.getStatus() == Status.DEPRECATED) {
+            getMethod.addAnnotation("", "Deprecated");
+        }
+        addComment(getMethod, node);
+
+        return getMethod;
+    }
+
+    /**
+     * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
+     * or to <code>genTOBuilder</code> as property.
+     *
+     * @param basePackageName
+     *            string contains the module package name
+     * @param schemaNode
+     *            data schema node which should be added as getter method to
+     *            <code>typeBuilder</code> or as a property to
+     *            <code>genTOBuilder</code> if is part of the list key
+     * @param typeBuilder
+     *            generated type builder for the list schema node
+     * @param genTOBuilder
+     *            generated TO builder for the list keys
+     * @param listKeys
+     *            list of string which contains names of the list keys
+     * @param module
+     *            current module
+     * @throws IllegalArgumentException
+     *             <ul>
+     *             <li>if <code>schemaNode</code> equals null</li>
+     *             <li>if <code>typeBuilder</code> equals null</li>
+     *             </ul>
+     */
+    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.");
+
+        if (schemaNode instanceof LeafSchemaNode) {
+            final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
+            final String leafName = leaf.getQName().getLocalName();
+            Type type = resolveLeafSchemaNodeAsMethod(typeBuilder, leaf, module);
+            if (listKeys.contains(leafName)) {
+                if (type == null) {
+                    resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true, module);
+                } else {
+                    resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, type, true);
+                }
+            }
+        } else if (!schemaNode.isAddedByUses()) {
+            if (schemaNode instanceof LeafListSchemaNode) {
+                resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode, module);
+            } else if (schemaNode instanceof ContainerSchemaNode) {
+                containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode);
+            } else if (schemaNode instanceof ChoiceSchemaNode) {
+                choiceToGeneratedType(module, basePackageName, typeBuilder, (ChoiceSchemaNode) schemaNode);
+            } else if (schemaNode instanceof ListSchemaNode) {
+                listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode);
+            }
+        }
+    }
+
+    private void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
+            final GeneratedTOBuilder genTOBuilder) {
+        checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
+
+        if (genTOBuilder != null) {
+            final GeneratedTransferObject genTO = genTOBuilder.toInstance();
+
+            // Fake the 'getKey()' for items, this is equivalent to constructGetter()
+            final MethodSignatureBuilder getMethod = typeBuilder.addMethod(getterMethodName("key", genTO));
+            getMethod.setReturnType(genTO);
+            getMethod.setComment("Returns Primary Key of Yang List Type");
+            genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
+        }
+    }
+
+    /**
+     * Selects the names of the list keys from <code>list</code> and returns
+     * them as the list of the strings
+     *
+     * @param list
+     *            of string with names of the list keys
+     * @return list of string which represents names of the list keys. If the
+     *         <code>list</code> contains no keys then the empty list is
+     *         returned.
+     */
+    private static List<String> listKeys(final ListSchemaNode list) {
+        final List<String> listKeys = new ArrayList<>();
+
+        final List<QName> keyDefinition = list.getKeyDefinition();
+        if (keyDefinition != null) {
+            for (final QName keyDef : keyDefinition) {
+                listKeys.add(keyDef.getLocalName());
+            }
+        }
+        return listKeys;
+    }
+
+    /**
+     * Generates for the <code>list</code> which contains any list keys special
+     * generated TO builder.
+     *
+     * @param packageName
+     *            string with package name to which the list belongs
+     * @param list
+     *            list schema node which is source of data about the list name
+     * @return generated TO builder which represents the keys of the
+     *         <code>list</code> or null if <code>list</code> is null or list of
+     *         key definitions is null or empty.
+     */
+    private static 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";
+            final String genTOName = BindingMapping.getClassName(listName);
+            genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
+        }
+        return genTOBuilder;
+    }
+
+    /**
+     * Builds generated TO builders for <code>typeDef</code> of type
+     * {@link UnionTypeDefinition} or {@link BitsTypeDefinition} which are
+     * also added to <code>typeBuilder</code> as enclosing transfer object.
+     *
+     * If more then one generated TO builder is created for enclosing then all
+     * of the generated TO builders are added to <code>typeBuilder</code> as
+     * enclosing transfer objects.
+     *
+     * @param typeDef
+     *            type definition which can be of type <code>UnionType</code> or
+     *            <code>BitsTypeDefinition</code>
+     * @param typeBuilder
+     *            generated type builder to which is added generated TO created
+     *            from <code>typeDef</code>
+     * @param leaf
+     *            string with name for generated TO builder
+     * @param parentModule
+     *            parent module
+     * @return generated TO builder for <code>typeDef</code>
+     */
+    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();
+        if (typeDef instanceof UnionTypeDefinition) {
+            final List<GeneratedTOBuilder> types = typeProvider
+                    .provideGeneratedTOBuildersForUnionTypeDef(packageName, (UnionTypeDefinition) typeDef,
+                            classNameFromLeaf, leaf);
+            genTOBuilders.addAll(types);
+
+            GeneratedTOBuilder resultTOBuilder;
+            if (types.isEmpty()) {
+                throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typeDef);
+            }
+            resultTOBuilder = types.remove(0);
+            for (final GeneratedTOBuilder genTOBuilder : types) {
+                resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
+            }
+
+            final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");
+            genPropBuilder.setReturnType(Types.CHAR_ARRAY);
+            resultTOBuilder.addEqualsIdentity(genPropBuilder);
+            resultTOBuilder.addHashIdentity(genPropBuilder);
+            resultTOBuilder.addToStringProperty(genPropBuilder);
+
+        } else if (typeDef instanceof BitsTypeDefinition) {
+            genTOBuilders.add(typeProvider.provideGeneratedTOBuilderForBitsTypeDefinition(
+                    packageName, typeDef, classNameFromLeaf, parentModule.getName()));
+        }
+        if (!genTOBuilders.isEmpty()) {
+            for (final GeneratedTOBuilder genTOBuilder : genTOBuilders) {
+                typeBuilder.addEnclosingTransferObject(genTOBuilder);
+            }
+            return genTOBuilders.get(0);
+        }
+        return null;
+
+    }
+
+    /**
+     * Adds the implemented types to type builder.
+     *
+     * The method passes through the list of <i>uses</i> in
+     * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
+     * generated type from {@link ModuleContext#groupings
+     * allGroupings} which is added as <i>implements type</i> to
+     * <code>builder</code>
+     *
+     * @param dataNodeContainer
+     *            element which contains the list of used YANG groupings
+     * @param builder
+     *            builder to which are added implemented types according to
+     *            <code>dataNodeContainer</code>
+     * @return generated type builder with all implemented types
+     */
+    private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
+            final GeneratedTypeBuilder builder) {
+        for (final UsesNode usesNode : dataNodeContainer.getUses()) {
+            final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath()).toInstance();
+            if (genType == null) {
+                throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
+                        + builder.getName());
+            }
+
+            builder.addImplementsType(genType);
+        }
+        return builder;
+    }
+
+    private GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path) {
+        for (final ModuleContext ctx : genCtx.values()) {
+            final GeneratedTypeBuilder result = ctx.getChildNode(path);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private GeneratedTypeBuilder findGroupingByPath(final SchemaPath path) {
+        for (final ModuleContext ctx : genCtx.values()) {
+            final GeneratedTypeBuilder result = ctx.getGrouping(path);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private GeneratedTypeBuilder findCaseByPath(final SchemaPath path) {
+        for (final ModuleContext ctx : genCtx.values()) {
+            final GeneratedTypeBuilder result = ctx.getCase(path);
+            if (result != null) {
+                return result;
+            }
+        }
+        return null;
+    }
+
+    private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) {
+        if (status == Status.DEPRECATED) {
+            builder.addAnnotation("", "Deprecated");
+        }
+    }
+}
index 21433b0313b5796f04a0ccfdbad603627c8ab7c5..89f5182c28552933c2b9c14b3ac97a063d540b08 100644 (file)
 package org.opendaylight.mdsal.binding.generator.impl;
 
 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.mdsal.binding.model.util.BindingGeneratorUtil.computeDefaultSUID;
-import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.encodeAngleBrackets;
-import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForAugmentedGeneratedType;
-import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForGeneratedType;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_OBJECT;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_ROOT;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIABLE;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIER;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.augmentable;
-import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN;
-import static org.opendaylight.mdsal.binding.model.util.Types.FUTURE;
-import static org.opendaylight.mdsal.binding.model.util.Types.VOID;
-import static org.opendaylight.mdsal.binding.model.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.findParentModule;
 
-import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import org.opendaylight.mdsal.binding.generator.api.BindingGenerator;
-import org.opendaylight.mdsal.binding.generator.spi.TypeProvider;
-import org.opendaylight.mdsal.binding.model.api.AccessModifier;
-import org.opendaylight.mdsal.binding.model.api.Constant;
-import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
-import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
-import org.opendaylight.mdsal.binding.model.api.Restrictions;
+import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeGenerator;
+import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeTypes;
 import org.opendaylight.mdsal.binding.model.api.Type;
-import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition;
-import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotationTypeBuilder;
-import org.opendaylight.mdsal.binding.model.api.type.builder.EnumBuilder;
-import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
-import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
-import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
-import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
-import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
-import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
-import org.opendaylight.mdsal.binding.model.util.BindingTypes;
-import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl;
-import org.opendaylight.mdsal.binding.model.util.TypeComments;
-import org.opendaylight.mdsal.binding.model.util.Types;
-import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedPropertyBuilderImpl;
-import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedTOBuilderImpl;
-import org.opendaylight.mdsal.binding.model.util.generated.type.builder.GeneratedTypeBuilderImpl;
-import org.opendaylight.mdsal.binding.yang.types.GroupingDefinitionDependencySort;
-import org.opendaylight.mdsal.binding.yang.types.TypeProviderImpl;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
-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;
-import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleImport;
-import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
-import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
-import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
-import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
-import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
-import org.opendaylight.yangtools.yang.model.util.ModuleDependencySort;
-import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
-import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
-import org.opendaylight.yangtools.yang.model.util.type.CompatUtils;
-import org.slf4j.Logger;
-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(':');
-
-    /**
-     * Comparator based on augment target path.
-     */
-    private static final Comparator<AugmentationSchemaNode> AUGMENT_COMP = (o1, o2) -> {
-        final Iterator<QName> thisIt = o1.getTargetPath().getPathFromRoot().iterator();
-        final Iterator<QName> otherIt = o2.getTargetPath().getPathFromRoot().iterator();
-
-        while (thisIt.hasNext()) {
-            if (!otherIt.hasNext()) {
-                return 1;
-            }
-
-            final int comp = thisIt.next().compareTo(otherIt.next());
-            if (comp != 0) {
-                return comp;
-            }
-        }
-
-        return otherIt.hasNext() ? -1 : 0;
-    };
-
-    /**
-     * 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<>();
-    private final boolean fullTypes;
-
-    /**
-     * Outer key represents the package name. Outer value represents map of all
-     * builders in the same package. Inner key represents the schema node name
-     * (in JAVA class/interface name format). Inner value represents instance of
-     * builder for schema node specified in key part.
-     */
-    private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
-
-    /**
-     * Provide methods for converting YANG types to JAVA types.
-     */
-    private TypeProvider typeProvider;
-
-    /**
-     * Holds reference to schema context to resolve data of augmented element
-     * when creating augmentation builder
-     */
-    private SchemaContext schemaContext;
-
-    public BindingGeneratorImpl() {
-        this(false);
-    }
-
-    public BindingGeneratorImpl(final boolean skinnyTypes) {
-        this.fullTypes = !skinnyTypes;
-    }
-
-    /**
-     * Resolves generated types from <code>context</code> schema nodes of all
-     * modules.
-     *
-     * Generated types are created for modules, groupings, types, containers,
-     * lists, choices, augments, rpcs, notification, identities.
-     *
-     * @param context
-     *            schema context which contains data about all schema nodes
-     *            saved in modules
-     * @return list of types (usually <code>GeneratedType</code>
-     *         <code>GeneratedTransferObject</code>which are generated from
-     *         <code>context</code> data.
-     * @throws IllegalArgumentException
-     *             if arg <code>context</code> is null
-     * @throws IllegalStateException
-     *             if <code>context</code> contain no modules
-     */
-    @Override
-    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;
-        final Set<Module> modules = context.getModules();
-        return generateTypes(context, modules);
-    }
 
+public class BindingGeneratorImpl implements BindingGenerator, BindingRuntimeGenerator {
     /**
      * Resolves generated types from <code>context</code> schema nodes only for
      * modules specified in <code>modules</code>
@@ -233,1931 +50,19 @@ public class BindingGeneratorImpl implements BindingGenerator {
      */
     @Override
     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.");
+        checkContext(context);
         checkArgument(modules != null, "Set of Modules cannot be NULL.");
-
-        schemaContext = context;
-        typeProvider = new TypeProviderImpl(context);
-        final List<Module> contextModules = ModuleDependencySort.sort(context.getModules());
-        genTypeBuilders = new HashMap<>();
-
-        for (final Module contextModule : contextModules) {
-            moduleToGenTypes(contextModule, context);
-        }
-        for (final Module contextModule : contextModules) {
-            allAugmentsToGenTypes(contextModule);
-        }
-
-        final List<Type> filteredGenTypes = new ArrayList<>();
-        for (final Module m : modules) {
-            final ModuleContext ctx = checkNotNull(genCtx.get(m), "Module context not found for module %s", m);
-            filteredGenTypes.addAll(ctx.getGeneratedTypes());
-            final Set<Type> additionalTypes = ((TypeProviderImpl) typeProvider).getAdditionalTypes().get(m);
-            if (additionalTypes != null) {
-                filteredGenTypes.addAll(additionalTypes);
-            }
-        }
-
-        return filteredGenTypes;
-    }
-
-    private void moduleToGenTypes(final Module m, final SchemaContext context) {
-        genCtx.put(m, new ModuleContext());
-        allTypeDefinitionsToGenTypes(m);
-        groupingsToGenTypes(m, m.getGroupings());
-        rpcMethodsToGenType(m);
-        allIdentitiesToGenTypes(m, context);
-        notificationsToGenType(m);
-
-        if (!m.getChildNodes().isEmpty()) {
-            final GeneratedTypeBuilder moduleType = moduleToDataType(m);
-            genCtx.get(m).addModuleNode(moduleType);
-            final String basePackageName = BindingMapping.getRootPackageName(m.getQNameModule());
-            resolveDataSchemaNodes(m, basePackageName, moduleType, moduleType, m.getChildNodes());
-        }
-    }
-
-    /**
-     * Converts all extended type definitions of module to the list of
-     * <code>Type</code> objects.
-     *
-     * @param module
-     *            module from which is obtained set of type definitions
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if module is null</li>
-     *             <li>if name of module is null</li>
-     *             </ul>
-     * @throws IllegalStateException
-     *             if set of type definitions from module is null
-     */
-    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);
-        final List<TypeDefinition<?>> typeDefinitions = it.allTypedefs();
-        checkState(typeDefinitions != null, "Type Definitions for module %s cannot be NULL.", module.getName());
-
-        for (final TypeDefinition<?> typedef : typeDefinitions) {
-            if (typedef != null) {
-                final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef,
-                        typedef);
-                if (type != null) {
-                    final ModuleContext ctx = genCtx.get(module);
-                    ctx.addTypedefType(typedef.getPath(), type);
-                    ctx.addTypeToSchema(type,typedef);
-                }
-            }
-        }
-    }
-
-    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, module);
-        annotateDeprecatedIfNecessary(node.getStatus(), genType);
-
-        genType.setModuleName(module.getName());
-
-        if (fullTypes) {
-            genType.setYangSourceDefinition(YangSourceDefinition.of(module, node));
-            TypeComments.description(node).ifPresent(genType::addComment);
-            node.getDescription().ifPresent(genType::setDescription);
-            node.getReference().ifPresent(genType::setReference);
-        }
-        genType.setSchemaPath(node.getPath().getPathFromRoot());
-        if (node instanceof DataNodeContainer) {
-            genCtx.get(module).addChildNodeType(node, genType);
-            groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
-            processUsesAugments((DataNodeContainer) node, module);
-        }
-        return genType;
-    }
-
-    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().orElse(null), genType,
-                node.getStatus());
-            resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes());
-        }
+        return new CodegenTypeGenerator(context).toTypes(modules);
     }
 
-    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().orElse(null),
-                    Types.listTypeFor(genType), node.getStatus());
-
-            final List<String> listKeys = listKeys(node);
-            final String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
-            final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
-            if (genTOBuilder != null) {
-                final Type identifierMarker = Types.parameterizedTypeFor(IDENTIFIER, genType);
-                final Type identifiableMarker = Types.parameterizedTypeFor(IDENTIFIABLE, genTOBuilder);
-                genTOBuilder.addImplementsType(identifierMarker);
-                genType.addImplementsType(identifiableMarker);
-            }
-
-            for (final DataSchemaNode schemaNode : node.getChildNodes()) {
-                if (!schemaNode.isAugmenting()) {
-                    addSchemaNodeToListBuilders(basePackageName, schemaNode, genType, genTOBuilder, listKeys, module);
-                }
-            }
-
-            // serialVersionUID
-            if (genTOBuilder != null) {
-                final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
-                prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
-                genTOBuilder.setSUID(prop);
-            }
-
-            typeBuildersToGenTypes(module, genType, genTOBuilder);
-        }
-    }
-
-    private void processUsesAugments(final DataNodeContainer node, final Module module) {
-        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
-        for (final UsesNode usesNode : node.getUses()) {
-            for (final AugmentationSchemaNode augment : usesNode.getAugmentations()) {
-                usesAugmentationToGenTypes(basePackageName, augment, module, usesNode, node);
-                processUsesAugments(augment, module);
-            }
-        }
-    }
-
-    /**
-     * Converts all <b>augmentation</b> of the module to the list
-     * <code>Type</code> objects.
-     *
-     * @param module
-     *            module from which is obtained list of all augmentation objects
-     *            to iterate over them
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if the module is null</li>
-     *             <li>if the name of module is null</li>
-     *             </ul>
-     * @throws IllegalStateException
-     *             if set of augmentations from module is null
-     */
-    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 = BindingMapping.getRootPackageName(module.getQNameModule());
-        for (final AugmentationSchemaNode augment : resolveAugmentations(module)) {
-            augmentationToGenTypes(basePackageName, augment, module);
-        }
-    }
-
-    /**
-     * Returns list of <code>AugmentationSchema</code> objects. The objects are
-     * sorted according to the length of their target path from the shortest to
-     * the longest.
-     *
-     * @param module
-     *            module from which is obtained list of all augmentation objects
-     * @return list of sorted <code>AugmentationSchema</code> objects obtained
-     *         from <code>module</code>
-     * @throws IllegalArgumentException
-     *             if module is null
-     * @throws IllegalStateException
-     *             if set of module augmentations is null
-     */
-    private static List<AugmentationSchemaNode> resolveAugmentations(final Module module) {
-        checkArgument(module != null, "Module reference cannot be NULL.");
-        checkState(module.getAugmentations() != null, "Augmentations Set cannot be NULL.");
-
-        final Set<AugmentationSchemaNode> augmentations = module.getAugmentations();
-        final List<AugmentationSchemaNode> sortedAugmentations = new ArrayList<>(augmentations);
-        sortedAugmentations.sort(AUGMENT_COMP);
-
-        return sortedAugmentations;
-    }
-
-    /**
-     * Create GeneratedTypeBuilder object from module argument.
-     *
-     * @param module
-     *            Module object from which builder will be created
-     * @return <code>GeneratedTypeBuilder</code> which is internal
-     *         representation of the module
-     * @throws IllegalArgumentException
-     *             if module is null
-     */
-    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);
-
-        if (fullTypes) {
-            moduleDataTypeBuilder.setYangSourceDefinition(YangSourceDefinition.of(module));
-            TypeComments.description(module).ifPresent(moduleDataTypeBuilder::addComment);
-            module.getDescription().ifPresent(moduleDataTypeBuilder::setDescription);
-            module.getReference().ifPresent(moduleDataTypeBuilder::setReference);
-        }
-        return moduleDataTypeBuilder;
-    }
-
-    /**
-     * Converts all <b>RPCs</b> input and output substatements of the module
-     * to the list of <code>Type</code> objects. In addition are to containers
-     * and lists which belong to input or output also part of returning list.
-     *
-     * @param module
-     *            module from which is obtained set of all rpc objects to
-     *            iterate over them
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if the module is null</li>
-     *             <li>if the name of module is null</li>
-     *             </ul>
-     * @throws IllegalStateException
-     *             if set of rpcs from module is null
-     */
-    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();
-        checkState(rpcDefinitions != null, "Set of rpcs from module " + module.getName() + " cannot be NULL.");
-        if (rpcDefinitions.isEmpty()) {
-            return;
-        }
-
-        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
-        final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
-        interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
-
-        if (fullTypes) {
-            interfaceBuilder.addComment(TypeComments.javadoc(
-                "Interface for implementing the following YANG RPCs defined in module <b>" + module.getName() + "</b>")
-                .get());
-            interfaceBuilder.setYangSourceDefinition(YangSourceDefinition.of(module, rpcDefinitions));
-        }
-
-        for (final RpcDefinition rpc : rpcDefinitions) {
-            if (rpc != null) {
-                final String rpcName = BindingMapping.getClassName(rpc.getQName());
-                final String rpcMethodName = BindingMapping.getPropertyName(rpcName);
-                final String rpcComment = encodeAngleBrackets(rpc.getDescription().orElse(null));
-                final MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
-                final ContainerSchemaNode input = rpc.getInput();
-                final ContainerSchemaNode output = rpc.getOutput();
-
-                // Do not refer to annotation class, as it may not be available at runtime
-                method.addAnnotation("javax.annotation", "CheckReturnValue");
-
-                //in case of implicit RPC input (StatementSource.CONTEXT),
-                // stay compatible (no input argument generated)
-                if (input != null && isExplicitStatement(input)) {
-                    processUsesAugments(input, module);
-                    final GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
-                    addImplementedInterfaceFromUses(input, inType);
-                    inType.addImplementsType(DATA_OBJECT);
-                    inType.addImplementsType(augmentable(inType));
-                    annotateDeprecatedIfNecessary(rpc.getStatus(), inType);
-                    resolveDataSchemaNodes(module, basePackageName, inType, inType, input.getChildNodes());
-                    genCtx.get(module).addChildNodeType(input, inType);
-                    final GeneratedType inTypeInstance = inType.toInstance();
-                    method.addParameter(inTypeInstance, "input");
-                }
-
-                Type outTypeInstance = VOID;
-                //in case of implicit RPC output (StatementSource.CONTEXT),
-                //stay compatible (Future<RpcResult<Void>> return type generated)
-                if (output != null && isExplicitStatement(output)) {
-                    processUsesAugments(output, module);
-                    final GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
-                    addImplementedInterfaceFromUses(output, outType);
-                    outType.addImplementsType(DATA_OBJECT);
-                    outType.addImplementsType(augmentable(outType));
-                    annotateDeprecatedIfNecessary(rpc.getStatus(), outType);
-                    resolveDataSchemaNodes(module, basePackageName, outType, outType, output.getChildNodes());
-                    genCtx.get(module).addChildNodeType(output, outType);
-                    outTypeInstance = outType.toInstance();
-                }
-
-                final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
-                method.setComment(rpcComment);
-                method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
-            }
-        }
-
-        genCtx.get(module).addTopLevelNodeType(interfaceBuilder);
-    }
-
-    private static boolean isExplicitStatement(final ContainerSchemaNode node) {
-        return node instanceof EffectiveStatement
-                && ((EffectiveStatement<?, ?>) node).getDeclared().getStatementSource() == StatementSource.DECLARATION;
-    }
-
-    /**
-     * Converts all <b>notifications</b> of the module to the list of
-     * <code>Type</code> objects. In addition are to this list added containers
-     * and lists which are part of this notification.
-     *
-     * @param module
-     *            module from which is obtained set of all notification objects
-     *            to iterate over them
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if the module equals null</li>
-     *             <li>if the name of module equals null</li>
-     *             </ul>
-     * @throws IllegalStateException
-     *             if set of notifications from module is null
-     */
-    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();
-        if (notifications.isEmpty()) {
-            return;
-        }
-
-        final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(module, "Listener");
-        listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
-        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
-
-        for (final NotificationDefinition notification : notifications) {
-            if (notification != null) {
-                processUsesAugments(notification, module);
-
-                final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName,
-                        notification, null, module);
-                annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
-                notificationInterface.addImplementsType(NOTIFICATION);
-                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(encodeAngleBrackets(notification.getDescription().orElse(null))).setReturnType(Types.VOID);
-            }
-        }
-
-        if (fullTypes) {
-            listenerInterface.setYangSourceDefinition(YangSourceDefinition.of(module, notifications));
-            listenerInterface.addComment(TypeComments.javadoc(
-                "Interface for receiving the following YANG notifications defined in module <b>" + module.getName()
-                + "</b>").get());
-        }
-
-        genCtx.get(module).addTopLevelNodeType(listenerInterface);
-    }
-
-    /**
-     * Converts all <b>identities</b> of the module to the list of
-     * <code>Type</code> objects.
-     *
-     * @param module
-     *            module from which is obtained set of all identity objects to
-     *            iterate over them
-     * @param context
-     *            schema context only used as input parameter for method
-     *            {@link BindingGeneratorImpl#identityToGenType}
-     *
-     */
-    private void allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
-        final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
-        final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
-
-        if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
-            for (final IdentitySchemaNode identity : schemaIdentities) {
-                identityToGenType(module, basePackageName, identity, context);
-            }
-        }
-    }
-
-    /**
-     * Converts the <b>identity</b> object to GeneratedType. Firstly it is
-     * created transport object builder. If identity contains base identity then
-     * reference to base identity is added to superior identity as its extend.
-     * If identity doesn't contain base identity then only reference to abstract
-     * class {@link org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
-     * BaseIdentity} is added
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string contains the module package name
-     * @param identity
-     *            IdentitySchemaNode which contains data about identity
-     * @param context
-     *            SchemaContext which is used to get package and name
-     *            information about base of identity
-     *
-     */
-    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 GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
-        final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
-        if (baseIdentities.isEmpty()) {
-            final GeneratedTOBuilderImpl gto = new GeneratedTOBuilderImpl(BaseIdentity.class.getPackage().getName(),
-                    BaseIdentity.class.getSimpleName());
-            newType.setExtendsType(gto.toInstance());
-        } else {
-            final IdentitySchemaNode baseIdentity = baseIdentities.iterator().next();
-            final Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
-            final String returnTypePkgName = BindingMapping.getRootPackageName(baseIdentityParentModule
-                    .getQNameModule());
-            final String returnTypeName = BindingMapping.getClassName(baseIdentity.getQName());
-            final GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName)
-            .toInstance();
-            newType.setExtendsType(gto);
-        }
-        newType.setAbstract(true);
-
-        if (fullTypes) {
-            newType.setYangSourceDefinition(YangSourceDefinition.of(module, identity));
-            TypeComments.description(identity).ifPresent(newType::addComment);
-            identity.getDescription().ifPresent(newType::setDescription);
-            identity.getReference().ifPresent(newType::setReference);
-        }
-        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(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
-            final QName name) {
-        return toBuilder.addConstant(typeForClass(QName.class), constantName, name);
-    }
-
-    /**
-     * Converts all <b>groupings</b> of the module to the list of
-     * <code>Type</code> objects. Firstly are groupings sorted according mutual
-     * dependencies. At least dependent (independent) groupings are in the list
-     * saved at first positions. For every grouping the record is added to map
-     * {@link ModuleContext#groupings allGroupings}
-     *
-     * @param module
-     *            current module
-     * @param groupings
-     *            collection of groupings from which types will be generated
-     *
-     */
-    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);
-        for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
-            groupingToGenType(basePackageName, grouping, module);
-        }
-    }
-
-    /**
-     * Converts individual grouping to GeneratedType. Firstly generated type
-     * builder is created and every child node of grouping is resolved to the
-     * method.
-     *
-     * @param basePackageName
-     *            string contains the module package name
-     * @param grouping
-     *            GroupingDefinition which contains data about grouping
-     * @param module
-     *            current 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, module);
-        annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
-        genCtx.get(module).addGroupingType(grouping.getPath(), genType);
-        resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes());
-        groupingsToGenTypes(module, grouping.getGroupings());
-        processUsesAugments(grouping, module);
-    }
-
-    /**
-     * Adds enumeration builder created from <code>enumTypeDef</code> to
-     * <code>typeBuilder</code>.
-     *
-     * Each <code>enumTypeDef</code> item is added to builder with its name and
-     * value.
-     *
-     * @param enumTypeDef
-     *            EnumTypeDefinition contains enum data
-     * @param enumName
-     *            string contains name which will be assigned to enumeration
-     *            builder
-     * @param typeBuilder
-     *            GeneratedTypeBuilder to which will be enum builder assigned
-     * @param module
-     *            Module in which type should be generated
-     * @return enumeration builder which contains data from
-     *         <code>enumTypeDef</code>
-     */
-    private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final QName enumName,
-            final GeneratedTypeBuilder typeBuilder, final Module module) {
-        if (enumTypeDef != null && typeBuilder != null && enumTypeDef.getQName().getLocalName() != null) {
-            final String enumerationName = BindingMapping.getClassName(enumName);
-            final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
-            final String enumTypedefDescription = encodeAngleBrackets(enumTypeDef.getDescription().orElse(null));
-            enumBuilder.setDescription(enumTypedefDescription);
-            enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
-            ModuleContext ctx = genCtx.get(module);
-            ctx.addInnerTypedefType(enumTypeDef.getPath(), enumBuilder);
-            return enumBuilder;
-        }
-        return null;
-    }
-
-    /**
-     * Generates type builder for <code>module</code>.
-     *
-     * @param module
-     *            Module which is source of package name for generated type
-     *            builder
-     * @param postfix
-     *            string which is added to the module class name representation
-     *            as suffix
-     * @return instance of GeneratedTypeBuilder which represents
-     *         <code>module</code>.
-     * @throws IllegalArgumentException
-     *             if <code>module</code> is null
-     */
-    private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
-        checkArgument(module != null, "Module reference cannot be NULL.");
-        final String packageName = BindingMapping.getRootPackageName(module.getQNameModule());
-        final String moduleName = BindingMapping.getClassName(module.getName()) + postfix;
-
-        final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
-
-        moduleBuilder.setModuleName(moduleName);
-        if (fullTypes) {
-            moduleBuilder.setYangSourceDefinition(YangSourceDefinition.of(module));
-            TypeComments.description(module).ifPresent(moduleBuilder::addComment);
-            module.getDescription().ifPresent(moduleBuilder::setDescription);
-            module.getReference().ifPresent(moduleBuilder::setReference);
-        }
-
-        return moduleBuilder;
-    }
-
-    /**
-     * Converts <code>augSchema</code> to list of <code>Type</code> which
-     * contains generated type for augmentation. In addition there are also
-     * generated types for all containers, list and choices which are child of
-     * <code>augSchema</code> node or a generated types for cases are added if
-     * augmented node is choice.
-     *
-     * @param augmentPackageName
-     *            string with the name of the package to which the augmentation
-     *            belongs
-     * @param augSchema
-     *            AugmentationSchema which is contains data about augmentation
-     *            (target path, childs...)
-     * @param module
-     *            current module
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>augmentPackageName</code> equals null</li>
-     *             <li>if <code>augSchema</code> equals null</li>
-     *             </ul>
-     * @throws IllegalStateException
-     *             if augment target path is null
-     */
-    private void augmentationToGenTypes(final String augmentPackageName, final AugmentationSchemaNode augSchema,
-            final Module module) {
-        checkArgument(augmentPackageName != null, "Package Name cannot be NULL.");
-        checkArgument(augSchema != null, "Augmentation Schema cannot be NULL.");
-        checkState(augSchema.getTargetPath() != null,
-                "Augmentation Schema does not contain Target Path (Target Path is NULL).");
-
-        processUsesAugments(augSchema, module);
-        final SchemaPath targetPath = augSchema.getTargetPath();
-        SchemaNode targetSchemaNode = null;
-
-        targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
-        if (targetSchemaNode instanceof DataSchemaNode && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-            if (targetSchemaNode instanceof DerivableSchemaNode) {
-                targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal().orElse(null);
-            }
-            if (targetSchemaNode == null) {
-                throw new IllegalStateException("Failed to find target node from grouping in augmentation " + augSchema
-                        + " in module " + module.getName());
-            }
-        }
-        if (targetSchemaNode == null) {
-            throw new IllegalArgumentException("augment target not found: " + targetPath);
-        }
-
-        GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath());
-        if (targetTypeBuilder == null) {
-            targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath());
-        }
-        if (targetTypeBuilder == null) {
-            throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
-        }
-
-        if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
-            final Type targetType = new ReferencedTypeImpl(targetTypeBuilder.getPackageName(),
-                    targetTypeBuilder.getName());
-            addRawAugmentGenTypeDefinition(module, augmentPackageName, augmentPackageName, targetType, augSchema);
-
-        } else {
-            generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance(),
-                    (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), null);
-        }
-    }
-
-    private void usesAugmentationToGenTypes(final String augmentPackageName, final AugmentationSchemaNode 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,
-                "Augmentation Schema does not contain Target Path (Target Path is NULL).");
-
-        processUsesAugments(augSchema, module);
-        final SchemaPath targetPath = augSchema.getTargetPath();
-        final SchemaNode targetSchemaNode = findOriginalTargetFromGrouping(targetPath, usesNode);
-        if (targetSchemaNode == null) {
-            throw new IllegalArgumentException("augment target not found: " + targetPath);
-        }
-
-        GeneratedTypeBuilder targetTypeBuilder = findChildNodeByPath(targetSchemaNode.getPath());
-        if (targetTypeBuilder == null) {
-            targetTypeBuilder = findCaseByPath(targetSchemaNode.getPath());
-        }
-        if (targetTypeBuilder == null) {
-            throw new NullPointerException("Target type not yet generated: " + targetSchemaNode);
-        }
-
-        if (!(targetSchemaNode instanceof ChoiceSchemaNode)) {
-            String packageName = augmentPackageName;
-            if (usesNodeParent instanceof SchemaNode) {
-                packageName = packageNameForAugmentedGeneratedType(augmentPackageName,
-                    ((SchemaNode) usesNodeParent).getPath());
-            }
-            addRawAugmentGenTypeDefinition(module, packageName, augmentPackageName, targetTypeBuilder.toInstance(),
-                    augSchema);
-        } else {
-            generateTypesFromAugmentedChoiceCases(module, augmentPackageName, targetTypeBuilder.toInstance(),
-                    (ChoiceSchemaNode) targetSchemaNode, augSchema.getChildNodes(), usesNodeParent);
-        }
-    }
-
-    /**
-     * Convenient method to find node added by uses statement.
-     *
-     * @param targetPath
-     *            node path
-     * @param parentUsesNode
-     *            parent of uses node
-     * @return node from its original location in grouping
-     */
-    private DataSchemaNode findOriginalTargetFromGrouping(final SchemaPath targetPath, final UsesNode parentUsesNode) {
-        final SchemaNode targetGrouping = findNodeInSchemaContext(schemaContext, parentUsesNode.getGroupingPath()
-                .getPathFromRoot());
-        if (!(targetGrouping instanceof GroupingDefinition)) {
-            throw new IllegalArgumentException("Failed to generate code for augment in " + parentUsesNode);
-        }
-
-        SchemaNode result = targetGrouping;
-        for (final QName node : targetPath.getPathFromRoot()) {
-            if (result instanceof DataNodeContainer) {
-                final QName resultNode = QName.create(result.getQName().getModule(), node.getLocalName());
-                result = ((DataNodeContainer) result).getDataChildByName(resultNode);
-            } else if (result instanceof ChoiceSchemaNode) {
-                result = findNamedCase((ChoiceSchemaNode) result, node.getLocalName());
-            }
-        }
-        if (result == null) {
-            return null;
-        }
-
-        if (result instanceof DerivableSchemaNode) {
-            DerivableSchemaNode castedResult = (DerivableSchemaNode) result;
-            Optional<? extends SchemaNode> originalNode = castedResult.getOriginal();
-            if (castedResult.isAddedByUses() && originalNode.isPresent()) {
-                result = originalNode.get();
-            }
-        }
-
-        if (result instanceof DataSchemaNode) {
-            DataSchemaNode resultDataSchemaNode = (DataSchemaNode) result;
-            if (resultDataSchemaNode.isAddedByUses()) {
-                // The original node is required, but we have only the copy of
-                // the original node.
-                // Maybe this indicates a bug in Yang parser.
-                throw new IllegalStateException("Failed to generate code for augment in " + parentUsesNode);
-            }
-
-            return resultDataSchemaNode;
-        }
-
-        throw new IllegalStateException(
-            "Target node of uses-augment statement must be DataSchemaNode. Failed to generate code for augment in "
-                    + parentUsesNode);
-    }
-
-    /**
-     * Returns a generated type builder for an augmentation.
-     *
-     * The name of the type builder is equal to the name of augmented node with
-     * serial number as suffix.
-     *
-     * @param module
-     *            current module
-     * @param augmentPackageName
-     *            string with contains the package name to which the augment
-     *            belongs
-     * @param basePackageName
-     *            string with the package name to which the augmented node
-     *            belongs
-     * @param targetTypeRef
-     *            target type
-     * @param augSchema
-     *            augmentation schema which contains data about the child nodes
-     *            and uses of augment
-     * @return generated type builder for augment
-     */
-    private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
-            final String basePackageName, final Type targetTypeRef, final AugmentationSchemaNode augSchema) {
-        Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
-        if (augmentBuilders == null) {
-            augmentBuilders = new HashMap<>();
-            genTypeBuilders.put(augmentPackageName, augmentBuilders);
-        }
-        final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
-
-        String augTypeName;
-        if (augIdentifier != null) {
-            augTypeName = BindingMapping.getClassName(augIdentifier);
-        } else {
-            augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName());
-        }
-
-        final GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
-
-        augTypeBuilder.addImplementsType(DATA_OBJECT);
-        augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
-        annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
-        addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
-
-        augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema.getChildNodes());
-        augmentBuilders.put(augTypeName, augTypeBuilder);
-
-        if (!augSchema.getChildNodes().isEmpty()) {
-            genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
-
-        }
-        genCtx.get(module).addAugmentType(augTypeBuilder);
-        return augTypeBuilder;
-    }
-
-    /**
-     *
-     * @param unknownSchemaNodes
-     * @return nodeParameter of UnknownSchemaNode
-     */
-    private static String getAugmentIdentifier(final List<UnknownSchemaNode> unknownSchemaNodes) {
-        for (final UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
-            final QName nodeType = unknownSchemaNode.getNodeType();
-            if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName())
-                    && YANG_EXT_NAMESPACE.equals(nodeType.getNamespace().toString())) {
-                return unknownSchemaNode.getNodeParameter();
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns first unique name for the augment generated type builder. The
-     * generated type builder name for augment consists from name of augmented
-     * node and serial number of its augmentation.
-     *
-     * @param builders
-     *            map of builders which were created in the package to which the
-     *            augmentation belongs
-     * @param genTypeName
-     *            string with name of augmented node
-     * @return string with unique name for augmentation builder
-     */
-    private static String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
-        int index = 1;
-        if (builders != null) {
-            while (builders.containsKey(genTypeName + index)) {
-                index = index + 1;
-            }
-        }
-        return genTypeName + index;
-    }
-
-    /**
-     * Adds the methods to <code>typeBuilder</code> which represent subnodes of
-     * node for which <code>typeBuilder</code> was created.
-     *
-     * The subnodes aren't mapped to the methods if they are part of grouping or
-     * augment (in this case are already part of them).
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string contains the module package name
-     * @param parent
-     *            generated type builder which represents any node. The subnodes
-     *            of this node are added to the <code>typeBuilder</code> as
-     *            methods. The subnode can be of type leaf, leaf-list, list,
-     *            container, choice.
-     * @param childOf
-     *            parent type
-     * @param schemaNodes
-     *            set of data schema nodes which are the children of the node
-     *            for which <code>typeBuilder</code> was created
-     * @return generated type builder which is the same builder as input
-     *         parameter. The getter methods (representing child nodes) could be
-     *         added to it.
-     */
-    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 (final DataSchemaNode schemaNode : schemaNodes) {
-                if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
-                    addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module);
-                }
-            }
-        }
-        return parent;
-    }
-
-    /**
-     * Adds the methods to <code>typeBuilder</code> what represents subnodes of
-     * node for which <code>typeBuilder</code> was created.
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string contains the module package name
-     * @param typeBuilder
-     *            generated type builder which represents any node. The subnodes
-     *            of this node are added to the <code>typeBuilder</code> as
-     *            methods. The subnode can be of type leaf, leaf-list, list,
-     *            container, choice.
-     * @param childOf
-     *            parent type
-     * @param schemaNodes
-     *            set of data schema nodes which are the children of the node
-     *            for which <code>typeBuilder</code> was created
-     * @return generated type builder which is the same object as the input
-     *         parameter <code>typeBuilder</code>. The getter method could be
-     *         added to it.
-     */
-    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 (final DataSchemaNode schemaNode : schemaNodes) {
-                if (!schemaNode.isAugmenting()) {
-                    addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
-                }
-            }
-        }
-        return typeBuilder;
-    }
-
-    /**
-     * Adds to <code>typeBuilder</code> a method which is derived from
-     * <code>schemaNode</code>.
-     *
-     * @param basePackageName
-     *            string with the module package name
-     * @param node
-     *            data schema node which is added to <code>typeBuilder</code> as
-     *            a method
-     * @param typeBuilder
-     *            generated type builder to which is <code>schemaNode</code>
-     *            added as a method.
-     * @param childOf
-     *            parent type
-     * @param module
-     *            current 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, module);
-            } else if (node instanceof LeafListSchemaNode) {
-                resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) node,module);
-            } else if (node instanceof ContainerSchemaNode) {
-                containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node);
-            } else if (node instanceof ListSchemaNode) {
-                listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node);
-            } else if (node instanceof ChoiceSchemaNode) {
-                choiceToGeneratedType(module, basePackageName, typeBuilder, (ChoiceSchemaNode) node);
-            } else {
-                // TODO: anyxml not yet supported
-                LOG.debug("Unable to add schema node {} as method in {}: unsupported type of node.", node.getClass(),
-                        typeBuilder.getFullyQualifiedName());
-            }
-        }
-    }
-
-    /**
-     * Converts <code>choiceNode</code> to the list of generated types for
-     * choice and its cases.
-     *
-     * The package names for choice and for its cases are created as
-     * concatenation of the module package (<code>basePackageName</code>) and
-     * names of all parents node.
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string with the module package name
-     * @param parent
-     *            parent type
-     * @param choiceNode
-     *            choice node which is mapped to generated type. Also child
-     *            nodes - cases are mapped to generated types.
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>basePackageName</code> is null</li>
-     *             <li>if <code>choiceNode</code> is null</li>
-     *             </ul>
-     */
-    private void choiceToGeneratedType(final Module module, final String basePackageName,
-            final GeneratedTypeBuilder parent, final ChoiceSchemaNode choiceNode) {
-        checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
-        checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
-
-        if (!choiceNode.isAddedByUses()) {
-            final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
-            final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
-            constructGetter(parent, choiceNode.getQName().getLocalName(),
-                    choiceNode.getDescription().orElse(null), choiceTypeBuilder, choiceNode.getStatus());
-            choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
-            annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
-            genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
-            generateTypesFromChoiceCases(module, basePackageName, choiceTypeBuilder.toInstance(), choiceNode);
-        }
-    }
-
-    /**
-     * Converts <code>caseNodes</code> set to list of corresponding generated
-     * types.
-     *
-     * For every <i>case</i> which isn't added through augment or <i>uses</i> is
-     * created generated type builder. The package names for the builder is
-     * created as concatenation of the module package (
-     * <code>basePackageName</code>) and names of all parents nodes of the
-     * concrete <i>case</i>. There is also relation "<i>implements type</i>"
-     * between every case builder and <i>choice</i> type
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string with the module package name
-     * @param refChoiceType
-     *            type which represents superior <i>case</i>
-     * @param choiceNode
-     *            choice case node which is mapped to generated type
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>basePackageName</code> equals null</li>
-     *             <li>if <code>refChoiceType</code> equals null</li>
-     *             <li>if <code>caseNodes</code> equals null</li>
-     *             </ul>
-     */
-    private void generateTypesFromChoiceCases(final Module module, final String basePackageName,
-            final Type refChoiceType, final ChoiceSchemaNode 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.");
-
-        for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) {
-            if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
-                final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode,
-                    module);
-                caseTypeBuilder.addImplementsType(refChoiceType);
-                annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder);
-                genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
-                genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
-                final Iterable<DataSchemaNode> caseChildNodes = caseNode.getChildNodes();
-                if (caseChildNodes != null) {
-                    final SchemaPath choiceNodeParentPath = choiceNode.getPath().getParent();
-
-                    if (!Iterables.isEmpty(choiceNodeParentPath.getPathFromRoot())) {
-                        SchemaNode parent = findDataSchemaNode(schemaContext, choiceNodeParentPath);
-
-                        if (parent instanceof AugmentationSchemaNode) {
-                            final AugmentationSchemaNode augSchema = (AugmentationSchemaNode) parent;
-                            final SchemaPath targetPath = augSchema.getTargetPath();
-                            SchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
-                            if (targetSchemaNode instanceof DataSchemaNode
-                                    && ((DataSchemaNode) targetSchemaNode).isAddedByUses()) {
-                                if (targetSchemaNode instanceof DerivableSchemaNode) {
-                                    targetSchemaNode = ((DerivableSchemaNode) targetSchemaNode).getOriginal()
-                                            .orElse(null);
-                                }
-                                if (targetSchemaNode == null) {
-                                    throw new IllegalStateException(
-                                            "Failed to find target node from grouping for augmentation " + augSchema
-                                                    + " in module " + module.getName());
-                                }
-                            }
-                            parent = targetSchemaNode;
-                        }
-
-                        Preconditions.checkState(parent != null, "Could not find Choice node parent %s",
-                                choiceNodeParentPath);
-                        GeneratedTypeBuilder childOfType = findChildNodeByPath(parent.getPath());
-                        if (childOfType == null) {
-                            childOfType = findGroupingByPath(parent.getPath());
-                        }
-                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, caseChildNodes);
-                    } else {
-                        resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, moduleToDataType(module),
-                                caseChildNodes);
-                    }
-               }
-            }
-            processUsesAugments(caseNode, module);
-        }
-    }
-
-    /**
-     * Generates list of generated types for all the cases of a choice which are
-     * added to the choice through the augment.
-     *
-     * @param module
-     *            current module
-     * @param basePackageName
-     *            string contains name of package to which augment belongs. If
-     *            an augmented choice is from an other package (pcg1) than an
-     *            augmenting choice (pcg2) then case's of the augmenting choice
-     *            will belong to pcg2.
-     * @param targetType
-     *            Type which represents target choice
-     * @param targetNode
-     *            node which represents target choice
-     * @param augmentedNodes
-     *            set of choice case nodes for which is checked if are/aren't
-     *            added to choice through augmentation
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>basePackageName</code> is null</li>
-     *             <li>if <code>targetType</code> is null</li>
-     *             <li>if <code>augmentedNodes</code> is null</li>
-     *             </ul>
-     */
-    private void generateTypesFromAugmentedChoiceCases(final Module module, final String basePackageName,
-            final Type targetType, final ChoiceSchemaNode targetNode, final Iterable<DataSchemaNode> augmentedNodes,
-            final DataNodeContainer usesNodeParent) {
-        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.");
-
-        for (final DataSchemaNode caseNode : augmentedNodes) {
-            if (caseNode != null) {
-                final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
-                final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode, module);
-                caseTypeBuilder.addImplementsType(targetType);
-
-                SchemaNode parent;
-                final SchemaPath nodeSp = targetNode.getPath();
-                parent = findDataSchemaNode(schemaContext, nodeSp.getParent());
-
-                GeneratedTypeBuilder childOfType = null;
-                if (parent instanceof Module) {
-                    childOfType = genCtx.get(parent).getModuleNode();
-                } else if (parent instanceof CaseSchemaNode) {
-                    childOfType = findCaseByPath(parent.getPath());
-                } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
-                    childOfType = findChildNodeByPath(parent.getPath());
-                } else if (parent instanceof GroupingDefinition) {
-                    childOfType = findGroupingByPath(parent.getPath());
-                }
-
-                if (childOfType == null) {
-                    throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
-                }
-
-                CaseSchemaNode node = null;
-                final String caseLocalName = caseNode.getQName().getLocalName();
-                if (caseNode instanceof CaseSchemaNode) {
-                    node = (CaseSchemaNode) caseNode;
-                } else if (findNamedCase(targetNode, caseLocalName) == null) {
-                    final String targetNodeLocalName = targetNode.getQName().getLocalName();
-                    for (DataSchemaNode dataSchemaNode : usesNodeParent.getChildNodes()) {
-                        if (dataSchemaNode instanceof ChoiceSchemaNode && targetNodeLocalName.equals(dataSchemaNode.getQName
-                                ().getLocalName())) {
-                            node = findNamedCase((ChoiceSchemaNode) dataSchemaNode, caseLocalName);
-                            break;
-                        }
-                    }
-                } else {
-                    node = findNamedCase(targetNode, caseLocalName);
-                }
-                final Iterable<DataSchemaNode> childNodes = node.getChildNodes();
-                if (childNodes != null) {
-                    resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder, childOfType, childNodes);
-                }
-                genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
-                genCtx.get(module).addChoiceToCaseMapping(targetType, caseTypeBuilder, node);
-            }
-        }
-    }
-
-    private static CaseSchemaNode findNamedCase(final ChoiceSchemaNode choice, final String caseName) {
-        final List<CaseSchemaNode> cases = choice.findCaseNodes(caseName);
-        return cases.isEmpty() ? null : cases.get(0);
-    }
-
-    private static boolean isInnerType(final LeafSchemaNode leaf, final TypeDefinition<?> type) {
-        // New parser with encapsulated type
-        if (leaf.getPath().equals(type.getPath())) {
-            return true;
-        }
-
-        // Embedded type definition with new parser. Also takes care of the old parser with bits
-        if (leaf.getPath().equals(type.getPath().getParent())) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Converts <code>leaf</code> to the getter method which is added to
-     * <code>typeBuilder</code>.
-     *
-     * @param typeBuilder
-     *            generated type builder to which is added getter method as
-     *            <code>leaf</code> mapping
-     * @param leaf
-     *            leaf schema node which is mapped as getter method which is
-     *            added to <code>typeBuilder</code>
-     * @param module
-     *            Module in which type was defined
-     * @return boolean value
-     *         <ul>
-     *         <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
-     *         null</li>
-     *         <li>true - in other cases</li>
-     *         </ul>
-     */
-    private Type resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf, final Module module) {
-        if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
-            return null;
-        }
-
-        final String leafName = leaf.getQName().getLocalName();
-        if (leafName == null) {
-            return null;
-        }
-
-        final Module parentModule = findParentModule(schemaContext, leaf);
-        Type returnType = null;
-
-        final TypeDefinition<?> typeDef = CompatUtils.compatLeafType(leaf);
-        if (isInnerType(leaf, typeDef)) {
-            if (typeDef instanceof EnumTypeDefinition) {
-                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
-                final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
-                final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
-                    typeBuilder, module);
-                if (enumBuilder != null) {
-                    returnType = enumBuilder.toInstance(typeBuilder);
-                }
-                ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
-            } else if (typeDef instanceof UnionTypeDefinition) {
-                GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
-                if (genTOBuilder != null) {
-                    returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
-                    // Store the inner type within the union so that we can find the reference for it
-                    genCtx.get(module).addInnerTypedefType(typeDef.getPath(), returnType);
-                }
-            } else if (typeDef instanceof BitsTypeDefinition) {
-                GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule);
-                if (genTOBuilder != null) {
-                    returnType = genTOBuilder.toInstance();
-                }
-            } else {
-                // It is constrained version of already declared type (inner declared type exists,
-                // onlyfor special cases (Enum, Union, Bits), which were already checked.
-                // In order to get proper class we need to look up closest derived type
-                // and apply restrictions from leaf type
-                final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
-                returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
-                        restrictions);
-            }
-        } else {
-            final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
-            returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
-        }
-
-        if (returnType == null) {
-            return null;
-        }
-
-        if (typeDef instanceof EnumTypeDefinition) {
-            ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
-        }
-
-        final String leafDesc = leaf.getDescription().orElse("");
-        final MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType,
-            leaf.getStatus());
-        processContextRefExtension(leaf, getter, parentModule);
-        return returnType;
-    }
-
-    private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
-        // Returns DerivedType in case of new parser.
-        final TypeDefinition<?> baseType = typeDef.getBaseType();
-        return baseType != null && baseType.getBaseType() != null ? baseType : typeDef;
-    }
-
-    private void processContextRefExtension(final LeafSchemaNode leaf, final MethodSignatureBuilder getter,
-            final Module module) {
-        for (final 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 = 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 = BindingMapping.getRootPackageName(module.getQNameModule());
-                } else if (length == 2) {
-                    final String prefix = iterator.next();
-                    final Module dependentModule = findModuleFromImports(module.getImports(), prefix);
-                    if (dependentModule == null) {
-                        throw new IllegalArgumentException("Failed to process context-reference: unknown prefix "
-                                + prefix);
-                    }
-                    identity = findIdentityByName(dependentModule.getIdentities(), iterator.next());
-                    basePackageName = BindingMapping.getRootPackageName(dependentModule.getQNameModule());
-                } else {
-                    throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
-                            + nodeParam);
-                }
-                if (identity == null) {
-                    throw new IllegalArgumentException("Failed to process context-reference: unknown identity "
-                            + nodeParam);
-                }
-
-                final Class<RoutingContext> clazz = RoutingContext.class;
-                final AnnotationTypeBuilder rc = getter.addAnnotation(clazz.getPackage().getName(),
-                        clazz.getSimpleName());
-                final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
-                final String genTypeName = BindingMapping.getClassName(identity.getQName().getLocalName());
-                rc.addParameter("value", packageName + "." + genTypeName + ".class");
-            }
-        }
-    }
-
-    private static IdentitySchemaNode findIdentityByName(final Set<IdentitySchemaNode> identities, final String name) {
-        for (final IdentitySchemaNode id : identities) {
-            if (id.getQName().getLocalName().equals(name)) {
-                return id;
-            }
-        }
-        return null;
-    }
-
-    private Module findModuleFromImports(final Set<ModuleImport> imports, final String prefix) {
-        for (final ModuleImport imp : imports) {
-            if (imp.getPrefix().equals(prefix)) {
-                return schemaContext.findModule(imp.getModuleName(), imp.getRevision()).orElse(null);
-            }
-        }
-        return null;
-    }
-
-    private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
-            final boolean isReadOnly, final Module module) {
-        if (leaf != null && toBuilder != null) {
-            Type returnType;
-            final TypeDefinition<?> typeDef = CompatUtils.compatLeafType(leaf);
-            if (typeDef instanceof UnionTypeDefinition) {
-                // GeneratedType for this type definition should have be already created
-                final QName qname = typeDef.getQName();
-                final Module unionModule = schemaContext.findModule(qname.getModule()).orElse(null);
-                final ModuleContext mc = genCtx.get(unionModule);
-                returnType = mc.getTypedefs().get(typeDef.getPath());
-                if (returnType == null) {
-                    // This may still be an inner type, try to find it
-                    returnType = mc.getInnerType(typeDef.getPath());
-                }
-            } else if (typeDef instanceof EnumTypeDefinition && typeDef.getBaseType() == null) {
-                // Annonymous enumeration (already generated, since it is inherited via uses).
-                LeafSchemaNode originalLeaf = (LeafSchemaNode) SchemaNodeUtils.getRootOriginalIfPossible(leaf);
-                QName qname = originalLeaf.getQName();
-                final Module enumModule =  schemaContext.findModule(qname.getModule()).orElse(null);
-                returnType = genCtx.get(enumModule).getInnerType(originalLeaf.getType().getPath());
-            } else {
-                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
-            }
-            return resolveLeafSchemaNodeAsProperty(toBuilder, leaf, returnType, isReadOnly);
-        }
-        return false;
-    }
-
-    /**
-     * Converts <code>leaf</code> schema node to property of generated TO
-     * builder.
-     *
-     * @param toBuilder
-     *            generated TO builder to which is <code>leaf</code> added as
-     *            property
-     * @param leaf
-     *            leaf schema node which is added to <code>toBuilder</code> as
-     *            property
-     * @param returnType
-     *            property type
-     * @param isReadOnly
-     *            boolean value which says if leaf property is|isn't read only
-     * @return boolean value
-     *         <ul>
-     *         <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
-     *         name equals null or if leaf is added by <i>uses</i>.</li>
-     *         <li>true - other cases</li>
-     *         </ul>
-     */
-    private static boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
-            final Type returnType, final boolean isReadOnly) {
-        if (returnType == null) {
-            return false;
-        }
-        final String leafName = leaf.getQName().getLocalName();
-        final String leafDesc = encodeAngleBrackets(leaf.getDescription().orElse(null));
-        final GeneratedPropertyBuilder propBuilder = toBuilder.addProperty(BindingMapping.getPropertyName(leafName));
-        propBuilder.setReadOnly(isReadOnly);
-        propBuilder.setReturnType(returnType);
-        propBuilder.setComment(leafDesc);
-        toBuilder.addEqualsIdentity(propBuilder);
-        toBuilder.addHashIdentity(propBuilder);
-        toBuilder.addToStringProperty(propBuilder);
-        return true;
-    }
-
-    /**
-     * Converts <code>node</code> leaf list schema node to getter method of
-     * <code>typeBuilder</code>.
-     *
-     * @param typeBuilder
-     *            generated type builder to which is <code>node</code> added as
-     *            getter method
-     * @param node
-     *            leaf list schema node which is added to
-     *            <code>typeBuilder</code> as getter method
-     * @param module module
-     * @return boolean value
-     *         <ul>
-     *         <li>true - if <code>node</code>, <code>typeBuilder</code>,
-     *         nodeName equal null or <code>node</code> is added by <i>uses</i></li>
-     *         <li>false - other cases</li>
-     *         </ul>
-     */
-    private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node,
-            final Module module) {
-        if (node == null || typeBuilder == null || node.isAddedByUses()) {
-            return false;
-        }
-
-        final QName nodeName = node.getQName();
-
-        final TypeDefinition<?> typeDef = node.getType();
-        final Module parentModule = findParentModule(schemaContext, node);
-
-        Type returnType = null;
-        if (typeDef.getBaseType() == null) {
-            if (typeDef instanceof EnumTypeDefinition) {
-                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node);
-                final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
-                final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName,
-                    typeBuilder,module);
-                returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
-                ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType);
-            } else if (typeDef instanceof UnionTypeDefinition) {
-                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, parentModule);
-                returnType = genTOBuilder.toInstance();
-            } else {
-                final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
-                returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);
-            }
-        } else {
-            final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
-            returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);
-        }
-
-        final ParameterizedType listType = Types.listTypeFor(returnType);
-        constructGetter(typeBuilder, nodeName.getLocalName(), node.getDescription().orElse(null), listType,
-            node.getStatus());
-        return true;
-    }
-
-    private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final TypeDefinition<?> typeDef,
-            final GeneratedTypeBuilder typeBuilder, final Module parentModule) {
-        final GeneratedTOBuilderImpl returnType = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
-                genTOBuilder.getName());
-
-        if (fullTypes) {
-            returnType.setYangSourceDefinition(YangSourceDefinition.of(parentModule, typeDef));
-            TypeComments.description(typeDef).ifPresent(returnType::addComment);
-            typeDef.getDescription().ifPresent(returnType::setDescription);
-            typeDef.getReference().ifPresent(returnType::setReference);
-        }
-        returnType.setSchemaPath(typeDef.getPath().getPathFromRoot());
-        returnType.setModuleName(parentModule.getName());
-
-        genTOBuilder.setTypedef(true);
-        genTOBuilder.setIsUnion(true);
-        TypeProviderImpl.addUnitsToGenTO(genTOBuilder, typeDef.getUnits().orElse(null));
-
-
-
-        final GeneratedTOBuilder unionBuilder = createUnionBuilder(genTOBuilder,typeBuilder);
-
-
-        final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
-        method.setReturnType(returnType);
-        method.addParameter(Types.STRING, "defaultValue");
-        method.setAccessModifier(AccessModifier.PUBLIC);
-        method.setStatic(true);
-
-        final Set<Type> types = ((TypeProviderImpl) typeProvider).getAdditionalTypes().get(parentModule);
-        if (types == null) {
-            ((TypeProviderImpl) typeProvider).getAdditionalTypes().put(parentModule,
-                    Sets.newHashSet(unionBuilder.toInstance()));
-        } else {
-            types.add(unionBuilder.toInstance());
-        }
-        return returnType.toInstance();
-    }
-
-    private static GeneratedTOBuilder createUnionBuilder(final GeneratedTOBuilder genTOBuilder, final GeneratedTypeBuilder typeBuilder) {
-        final String outerCls = Types.getOuterClassName(genTOBuilder);
-        final StringBuilder name;
-        if (outerCls != null) {
-            name = new StringBuilder(outerCls);
-        } else {
-            name = new StringBuilder();
-        }
-        name.append(genTOBuilder.getName());
-        name.append("Builder");
-        final GeneratedTOBuilderImpl unionBuilder = new GeneratedTOBuilderImpl(typeBuilder.getPackageName(),name.toString());
-        unionBuilder.setIsUnionBuilder(true);
-        return unionBuilder;
-    }
-
-    private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
-            final Module module) {
-        return addDefaultInterfaceDefinition(packageName, schemaNode, null, module);
-    }
-
-    /**
-     * Instantiates generated type builder with <code>packageName</code> and
-     * <code>schemaNode</code>.
-     *
-     * The new builder always implements
-     * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br>
-     * If <code>schemaNode</code> is instance of GroupingDefinition it also
-     * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
-     * Augmentable}.<br>
-     * If <code>schemaNode</code> is instance of
-     * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
-     * DataNodeContainer} it can also implement nodes which are specified in
-     * <i>uses</i>.
-     *
-     * @param packageName
-     *            string with the name of the package to which
-     *            <code>schemaNode</code> belongs.
-     * @param schemaNode
-     *            schema node for which is created generated type builder
-     * @param parent
-     *            parent type (can be null)
-     * @return generated type builder <code>schemaNode</code>
-     */
-    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);
-        } else {
-            it.addImplementsType(BindingTypes.childOf(parent));
-        }
-        if (!(schemaNode instanceof GroupingDefinition)) {
-            it.addImplementsType(augmentable(it));
-        }
-
-        if (schemaNode instanceof DataNodeContainer) {
-            groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
-            addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
-        }
-
-        return it;
-    }
-
-    /**
-     * Wraps the calling of the same overloaded method.
-     *
-     * @param packageName
-     *            string with the package name to which returning generated type
-     *            builder belongs
-     * @param schemaNode
-     *            schema node which provide data about the schema node name
-     * @return generated type builder for <code>schemaNode</code>
-     */
-    private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
-        return addRawInterfaceDefinition(packageName, schemaNode, "");
-    }
-
-    /**
-     * Returns reference to generated type builder for specified
-     * <code>schemaNode</code> with <code>packageName</code>.
-     *
-     * Firstly the generated type builder is searched in
-     * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
-     * found it is created and added to <code>genTypeBuilders</code>.
-     *
-     * @param packageName
-     *            string with the package name to which returning generated type
-     *            builder belongs
-     * @param schemaNode
-     *            schema node which provide data about the schema node name
-     * @param prefix
-     *            return type name prefix
-     * @return generated type builder for <code>schemaNode</code>
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>schemaNode</code> is null</li>
-     *             <li>if <code>packageName</code> is null</li>
-     *             <li>if QName of schema node is null</li>
-     *             <li>if schemaNode name is null</li>
-     *             </ul>
-     *
-     */
-    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.");
-        final String schemaNodeName = schemaNode.getQName().getLocalName();
-        checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
-
-        String genTypeName;
-        if (prefix == null) {
-            genTypeName = BindingMapping.getClassName(schemaNodeName);
-        } else {
-            genTypeName = prefix + BindingMapping.getClassName(schemaNodeName);
-        }
-
-        // 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());
-
-        if (fullTypes) {
-            newType.setYangSourceDefinition(YangSourceDefinition.of(module, schemaNode));
-            TypeComments.description(schemaNode).ifPresent(newType::addComment);
-            schemaNode.getDescription().ifPresent(newType::setDescription);
-            schemaNode.getReference().ifPresent(newType::setReference);
-        }
-        newType.setSchemaPath(schemaNode.getPath().getPathFromRoot());
-        newType.setModuleName(module.getName());
-
-        if (!genTypeBuilders.containsKey(packageName)) {
-            final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
-            builders.put(genTypeName, newType);
-            genTypeBuilders.put(packageName, builders);
-        } else {
-            final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
-            if (!builders.containsKey(genTypeName)) {
-                builders.put(genTypeName, newType);
-            }
-        }
-        return newType;
-    }
-
-    /**
-     * Creates the name of the getter method name from <code>localName</code>.
-     *
-     * @param localName
-     *            string with the name of the getter method
-     * @param returnType
-     *            return type
-     * @return string with the name of the getter method for
-     *         <code>methodName</code> in JAVA method format
-     */
-    public static String getterMethodName(final String localName, final Type returnType) {
-        final StringBuilder method = new StringBuilder();
-        if (BOOLEAN.equals(returnType)) {
-            method.append("is");
-        } else {
-            method.append("get");
-        }
-        final String name = BindingMapping.toFirstUpper(BindingMapping.getPropertyName(localName));
-        method.append(name);
-        return method.toString();
-    }
-
-    /**
-     * Created a method signature builder as part of
-     * <code>interfaceBuilder</code>.
-     *
-     * The method signature builder is created for the getter method of
-     * <code>schemaNodeName</code>. Also <code>comment</code> and
-     * <code>returnType</code> information are added to the builder.
-     *
-     * @param interfaceBuilder
-     *            generated type builder for which the getter method should be
-     *            created
-     * @param schemaNodeName
-     *            string with schema node name. The name will be the part of the
-     *            getter method name.
-     * @param comment
-     *            string with comment for the getter method
-     * @param returnType
-     *            type which represents the return type of the getter method
-     * @param status
-     *            status from yang file, for deprecated annotation
-     * @return method signature builder which represents the getter method of
-     *         <code>interfaceBuilder</code>
-     */
-    private static MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
-            final String schemaNodeName, final String comment, final Type returnType, final Status status) {
-        final MethodSignatureBuilder getMethod = interfaceBuilder
-                .addMethod(getterMethodName(schemaNodeName, returnType));
-        if (status == Status.DEPRECATED) {
-            getMethod.addAnnotation("", "Deprecated");
-        }
-        getMethod.setComment(encodeAngleBrackets(comment));
-        getMethod.setReturnType(returnType);
-        return getMethod;
-    }
-
-    /**
-     * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
-     * or to <code>genTOBuilder</code> as property.
-     *
-     * @param basePackageName
-     *            string contains the module package name
-     * @param schemaNode
-     *            data schema node which should be added as getter method to
-     *            <code>typeBuilder</code> or as a property to
-     *            <code>genTOBuilder</code> if is part of the list key
-     * @param typeBuilder
-     *            generated type builder for the list schema node
-     * @param genTOBuilder
-     *            generated TO builder for the list keys
-     * @param listKeys
-     *            list of string which contains names of the list keys
-     * @param module
-     *            current module
-     * @throws IllegalArgumentException
-     *             <ul>
-     *             <li>if <code>schemaNode</code> equals null</li>
-     *             <li>if <code>typeBuilder</code> equals null</li>
-     *             </ul>
-     */
-    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.");
-
-        if (schemaNode instanceof LeafSchemaNode) {
-            final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
-            final String leafName = leaf.getQName().getLocalName();
-            Type type = resolveLeafSchemaNodeAsMethod(typeBuilder, leaf, module);
-            if (listKeys.contains(leafName)) {
-                if (type == null) {
-                    resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true, module);
-                } else {
-                    resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, type, true);
-                }
-            }
-        } else if (!schemaNode.isAddedByUses()) {
-            if (schemaNode instanceof LeafListSchemaNode) {
-                resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode, module);
-            } else if (schemaNode instanceof ContainerSchemaNode) {
-                containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode);
-            } else if (schemaNode instanceof ChoiceSchemaNode) {
-                choiceToGeneratedType(module, basePackageName, typeBuilder, (ChoiceSchemaNode) schemaNode);
-            } else if (schemaNode instanceof ListSchemaNode) {
-                listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode);
-            }
-        }
-    }
-
-    private void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
-            final GeneratedTOBuilder genTOBuilder) {
-        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);
-        }
-    }
-
-    /**
-     * Selects the names of the list keys from <code>list</code> and returns
-     * them as the list of the strings
-     *
-     * @param list
-     *            of string with names of the list keys
-     * @return list of string which represents names of the list keys. If the
-     *         <code>list</code> contains no keys then the empty list is
-     *         returned.
-     */
-    private static List<String> listKeys(final ListSchemaNode list) {
-        final List<String> listKeys = new ArrayList<>();
-
-        final List<QName> keyDefinition = list.getKeyDefinition();
-        if (keyDefinition != null) {
-            for (final QName keyDef : keyDefinition) {
-                listKeys.add(keyDef.getLocalName());
-            }
-        }
-        return listKeys;
-    }
-
-    /**
-     * Generates for the <code>list</code> which contains any list keys special
-     * generated TO builder.
-     *
-     * @param packageName
-     *            string with package name to which the list belongs
-     * @param list
-     *            list schema node which is source of data about the list name
-     * @return generated TO builder which represents the keys of the
-     *         <code>list</code> or null if <code>list</code> is null or list of
-     *         key definitions is null or empty.
-     */
-    private static 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";
-            final String genTOName = BindingMapping.getClassName(listName);
-            genTOBuilder = new GeneratedTOBuilderImpl(packageName, genTOName);
-        }
-        return genTOBuilder;
-    }
-
-    /**
-     * Builds generated TO builders for <code>typeDef</code> of type
-     * {@link UnionTypeDefinition} or {@link BitsTypeDefinition} which are
-     * also added to <code>typeBuilder</code> as enclosing transfer object.
-     *
-     * If more then one generated TO builder is created for enclosing then all
-     * of the generated TO builders are added to <code>typeBuilder</code> as
-     * enclosing transfer objects.
-     *
-     * @param typeDef
-     *            type definition which can be of type <code>UnionType</code> or
-     *            <code>BitsTypeDefinition</code>
-     * @param typeBuilder
-     *            generated type builder to which is added generated TO created
-     *            from <code>typeDef</code>
-     * @param leaf
-     *            string with name for generated TO builder
-     * @param parentModule
-     *            parent module
-     * @return generated TO builder for <code>typeDef</code>
-     */
-    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();
-        if (typeDef instanceof UnionTypeDefinition) {
-            final List<GeneratedTOBuilder> types = ((TypeProviderImpl) typeProvider)
-                    .provideGeneratedTOBuildersForUnionTypeDef(packageName, (UnionTypeDefinition) typeDef,
-                            classNameFromLeaf, leaf);
-            genTOBuilders.addAll(types);
-
-            GeneratedTOBuilder resultTOBuilder;
-            if (types.isEmpty()) {
-                throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typeDef);
-            }
-            resultTOBuilder = types.remove(0);
-            for (final GeneratedTOBuilder genTOBuilder : types) {
-                resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
-            }
-
-            final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");
-            genPropBuilder.setReturnType(Types.CHAR_ARRAY);
-            resultTOBuilder.addEqualsIdentity(genPropBuilder);
-            resultTOBuilder.addHashIdentity(genPropBuilder);
-            resultTOBuilder.addToStringProperty(genPropBuilder);
-
-        } else if (typeDef instanceof BitsTypeDefinition) {
-            genTOBuilders.add(((TypeProviderImpl) typeProvider).provideGeneratedTOBuilderForBitsTypeDefinition(
-                    packageName, typeDef, classNameFromLeaf, parentModule.getName()));
-        }
-        if (!genTOBuilders.isEmpty()) {
-            for (final GeneratedTOBuilder genTOBuilder : genTOBuilders) {
-                typeBuilder.addEnclosingTransferObject(genTOBuilder);
-            }
-            return genTOBuilders.get(0);
-        }
-        return null;
-
-    }
-
-    /**
-     * Adds the implemented types to type builder.
-     *
-     * The method passes through the list of <i>uses</i> in
-     * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
-     * generated type from {@link ModuleContext#groupings
-     * allGroupings} which is added as <i>implements type</i> to
-     * <code>builder</code>
-     *
-     * @param dataNodeContainer
-     *            element which contains the list of used YANG groupings
-     * @param builder
-     *            builder to which are added implemented types according to
-     *            <code>dataNodeContainer</code>
-     * @return generated type builder with all implemented types
-     */
-    private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
-            final GeneratedTypeBuilder builder) {
-        for (final UsesNode usesNode : dataNodeContainer.getUses()) {
-            final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath()).toInstance();
-            if (genType == null) {
-                throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
-                        + builder.getName());
-            }
-
-            builder.addImplementsType(genType);
-        }
-        return builder;
-    }
-
-    private GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path) {
-        for (final ModuleContext ctx : genCtx.values()) {
-            final GeneratedTypeBuilder result = ctx.getChildNode(path);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
-    private GeneratedTypeBuilder findGroupingByPath(final SchemaPath path) {
-        for (final ModuleContext ctx : genCtx.values()) {
-            final GeneratedTypeBuilder result = ctx.getGrouping(path);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
-    private GeneratedTypeBuilder findCaseByPath(final SchemaPath path) {
-        for (final ModuleContext ctx : genCtx.values()) {
-            final GeneratedTypeBuilder result = ctx.getCase(path);
-            if (result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
-    public Map<Module, ModuleContext> getModuleContexts() {
-        return genCtx;
+    @Override
+    public BindingRuntimeTypes generateTypeMapping(final SchemaContext context) {
+        checkContext(context);
+        return new RuntimeTypeGenerator(context).toTypeMapping();
     }
 
-    private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) {
-        if (status == Status.DEPRECATED) {
-            builder.addAnnotation("", "Deprecated");
-        }
+    private static void checkContext(final SchemaContext context) {
+        checkArgument(context != null, "Schema Context reference cannot be NULL.");
+        checkState(context.getModules() != null, "Schema Context does not contain defined modules.");
     }
 }
diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/CodegenTypeGenerator.java
new file mode 100644 (file)
index 0000000..ba08f9c
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.impl;
+
+import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.encodeAngleBrackets;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.api.YangSourceDefinition;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
+import org.opendaylight.mdsal.binding.model.util.TypeComments;
+import org.opendaylight.mdsal.binding.yang.types.TypeProviderImpl;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+final class CodegenTypeGenerator extends AbstractTypeGenerator {
+    CodegenTypeGenerator(final SchemaContext context) {
+        super(context, new TypeProviderImpl(context));
+    }
+
+    List<Type> toTypes(final Set<Module> modules) {
+        final List<Type> filteredGenTypes = new ArrayList<>();
+        for (final Module m : modules) {
+            filteredGenTypes.addAll(moduleContext(m).getGeneratedTypes());
+            final Set<Type> additionalTypes = typeProvider().getAdditionalTypes().get(m);
+            if (additionalTypes != null) {
+                filteredGenTypes.addAll(additionalTypes);
+            }
+        }
+        return filteredGenTypes;
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilderBase<?> genType, final Module module,
+            final SchemaNode node) {
+        genType.setYangSourceDefinition(YangSourceDefinition.of(module, node));
+        TypeComments.description(node).ifPresent(genType::addComment);
+        node.getDescription().ifPresent(genType::setDescription);
+        node.getReference().ifPresent(genType::setReference);
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilderBase<?> genType, final Module module) {
+        genType.setYangSourceDefinition(YangSourceDefinition.of(module));
+        TypeComments.description(module).ifPresent(genType::addComment);
+        module.getDescription().ifPresent(genType::setDescription);
+        module.getReference().ifPresent(genType::setReference);
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilder interfaceBuilder, final Module module,
+            final String description, final Set<?  extends SchemaNode> nodes) {
+        interfaceBuilder.addComment(TypeComments.javadoc("Interface for implementing the following YANG " + description
+            + " defined in module <b>" + module.getName() + "</b>").get());
+        interfaceBuilder.setYangSourceDefinition(YangSourceDefinition.of(module, nodes));
+    }
+
+    @Override
+    void addComment(final TypeMemberBuilder<?> genType, final DocumentedNode node) {
+        final Optional<String> optDesc = node.getDescription();
+        if (optDesc.isPresent()) {
+            genType.setComment(encodeAngleBrackets(optDesc.get()));
+        }
+    }
+}
index f940efe3de497b2c58a8a53510435832df9b1a87..b1bc4785cbfd7edda25beb441b692edab0460df7 100644 (file)
@@ -27,6 +27,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -42,10 +43,7 @@ public final class ModuleContext {
     private final Set<GeneratedTypeBuilder> topLevelNodes = new HashSet<>();
     private final List<GeneratedTypeBuilder> augmentations = new ArrayList<>();
     private final BiMap<Type, AugmentationSchemaNode> typeToAugmentation = HashBiMap.create();
-
-    private final Map<Type,Object> typeToSchema = new HashMap<>();
-
-
+    private final Map<Type, WithStatus> typeToSchema = new HashMap<>();
     private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
     private final BiMap<Type, CaseSchemaNode> caseTypeToSchema = HashBiMap.create();
 
@@ -199,7 +197,7 @@ public final class ModuleContext {
      *
      * @return Mapping from type to corresponding schema
      */
-    public Map<Type, Object> getTypeToSchema() {
+    public Map<Type, WithStatus> getTypeToSchema() {
         return Collections.unmodifiableMap(typeToSchema);
     }
 
diff --git a/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java b/binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/RuntimeTypeGenerator.java
new file mode 100644 (file)
index 0000000..59a3d18
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.impl;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeTypes;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
+import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
+import org.opendaylight.mdsal.binding.yang.types.TypeProviderImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+final class RuntimeTypeGenerator extends AbstractTypeGenerator {
+    RuntimeTypeGenerator(final SchemaContext context) {
+        // TODO: instantiate a different subclass of TypeProviderImpl
+        super(context, new TypeProviderImpl(context));
+    }
+
+    BindingRuntimeTypes toTypeMapping() {
+        final Map<Type, AugmentationSchemaNode> augmentationToSchema = new HashMap<>();
+        final BiMap<Type, WithStatus> typeToDefiningSchema = HashBiMap.create();
+        final Multimap<Type, Type> choiceToCases = HashMultimap.create();
+        final Map<QName, Type> identities = new HashMap<>();
+
+        for (final ModuleContext ctx : moduleContexts()) {
+            augmentationToSchema.putAll(ctx.getTypeToAugmentation());
+            typeToDefiningSchema.putAll(ctx.getTypeToSchema());
+
+            choiceToCases.putAll(ctx.getChoiceToCases());
+            identities.putAll(ctx.getIdentities());
+        }
+
+        return new BindingRuntimeTypes(augmentationToSchema, typeToDefiningSchema, choiceToCases, identities);
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilderBase<?> genType, final Module module) {
+        // No-op
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilderBase<?> genType, final Module module, final SchemaNode node) {
+        // No-op
+    }
+
+    @Override
+    void addCodegenInformation(final GeneratedTypeBuilder interfaceBuilder, final Module module, final String string,
+            final Set<? extends SchemaNode> nodes) {
+        // No-op
+    }
+
+    @Override
+    void addComment(final TypeMemberBuilder<?> genType, final DocumentedNode node) {
+        // No-op
+    }
+}
index cde50e401478cdb961571d7bd69c6b8d1af59083..afa0d4b6226585834fa89455ff12401145e6c703 100644 (file)
@@ -7,17 +7,18 @@
  */
 package org.opendaylight.mdsal.binding.generator.util;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.BiMap;
-import com.google.common.collect.FluentIterable;
 import com.google.common.collect.HashBiMap;
-import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimap;
+import com.google.common.collect.Iterables;
 import java.util.AbstractMap.SimpleEntry;
 import java.util.Collection;
 import java.util.HashMap;
@@ -26,10 +27,10 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.generator.api.BindingRuntimeTypes;
 import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.mdsal.binding.generator.impl.BindingGeneratorImpl;
 import org.opendaylight.mdsal.binding.generator.impl.BindingSchemaContextUtils;
-import org.opendaylight.mdsal.binding.generator.impl.ModuleContext;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
@@ -47,7 +48,7 @@ import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
@@ -56,6 +57,7 @@ import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
 /**
  *
  * Runtime Context for Java YANG Binding classes
@@ -76,22 +78,19 @@ import org.slf4j.LoggerFactory;
 public class BindingRuntimeContext implements Immutable {
     private static final Logger LOG = LoggerFactory.getLogger(BindingRuntimeContext.class);
     private static final char DOT = '.';
+
+    private final BindingRuntimeTypes runtimeTypes;
     private final ClassLoadingStrategy strategy;
     private final SchemaContext schemaContext;
 
-    private final Map<Type, AugmentationSchemaNode> augmentationToSchema = new HashMap<>();
-    private final BiMap<Type, Object> typeToDefiningSchema = HashBiMap.create();
-    private final Multimap<Type, Type> choiceToCases = HashMultimap.create();
-    private final Map<QName, Type> identities = new HashMap<>();
-
     private final LoadingCache<QName, Class<?>> identityClasses = CacheBuilder.newBuilder().weakValues().build(
         new CacheLoader<QName, Class<?>>() {
             @Override
             public Class<?> load(final QName key) {
-                final Type identityType = identities.get(key);
-                Preconditions.checkArgument(identityType != null, "Supplied QName %s is not a valid identity", key);
+                final java.util.Optional<Type> identityType = runtimeTypes.findIdentity(key);
+                checkArgument(identityType.isPresent(), "Supplied QName %s is not a valid identity", key);
                 try {
-                    return strategy.loadClass(identityType);
+                    return strategy.loadClass(identityType.get());
                 } catch (final ClassNotFoundException e) {
                     throw new IllegalArgumentException("Required class " + identityType + "was not found.", e);
                 }
@@ -101,19 +100,7 @@ public class BindingRuntimeContext implements Immutable {
     private BindingRuntimeContext(final ClassLoadingStrategy strategy, final SchemaContext schema) {
         this.strategy = strategy;
         this.schemaContext = schema;
-
-        final BindingGeneratorImpl generator = new BindingGeneratorImpl(true);
-        generator.generateTypes(schema);
-        final Map<Module, ModuleContext> modules = generator.getModuleContexts();
-
-        for (final ModuleContext ctx : modules.values()) {
-            augmentationToSchema.putAll(ctx.getTypeToAugmentation());
-            typeToDefiningSchema.putAll(ctx.getTypeToSchema());
-
-            ctx.getTypedefs();
-            choiceToCases.putAll(ctx.getChoiceToCases());
-            identities.putAll(ctx.getIdentities());
-        }
+        runtimeTypes = new BindingGeneratorImpl().generateTypeMapping(schema);
     }
 
     /**
@@ -168,9 +155,9 @@ public class BindingRuntimeContext implements Immutable {
      * @throws IllegalArgumentException If supplied class is not an augmentation
      */
     public @Nullable AugmentationSchemaNode getAugmentationDefinition(final Class<?> augClass) {
-        Preconditions.checkArgument(Augmentation.class.isAssignableFrom(augClass),
+        checkArgument(Augmentation.class.isAssignableFrom(augClass),
             "Class %s does not represent augmentation", augClass);
-        return augmentationToSchema.get(referencedType(augClass));
+        return runtimeTypes.findAugmentation(referencedType(augClass)).orElse(null);
     }
 
     /**
@@ -188,14 +175,15 @@ public class BindingRuntimeContext implements Immutable {
      * @return Schema node, from which class was generated.
      */
     public DataSchemaNode getSchemaDefinition(final Class<?> cls) {
-        Preconditions.checkArgument(!Augmentation.class.isAssignableFrom(cls),"Supplied class must not be augmentation (%s is)", cls);
-        return (DataSchemaNode) typeToDefiningSchema.get(referencedType(cls));
+        checkArgument(!Augmentation.class.isAssignableFrom(cls), "Supplied class must not be augmentation (%s is)",
+            cls);
+        return (DataSchemaNode) runtimeTypes.findSchema(referencedType(cls)).orElse(null);
     }
 
     public Entry<AugmentationIdentifier, AugmentationSchemaNode> getResolvedAugmentationSchema(
             final DataNodeContainer target, final Class<? extends Augmentation<?>> aug) {
         final AugmentationSchemaNode origSchema = getAugmentationDefinition(aug);
-        Preconditions.checkArgument(origSchema != null, "Augmentation %s is not known in current schema context",aug);
+        checkArgument(origSchema != null, "Augmentation %s is not known in current schema context", aug);
         /*
          * FIXME: Validate augmentation schema lookup
          *
@@ -241,9 +229,9 @@ public class BindingRuntimeContext implements Immutable {
      *         the given context.
      * @throws IllegalArgumentException If supplied class does not represent case.
      */
-    public Optional<CaseSchemaNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) throws IllegalArgumentException {
+    public Optional<CaseSchemaNode> getCaseSchemaDefinition(final ChoiceSchemaNode schema, final Class<?> childClass) {
         final DataSchemaNode origSchema = getSchemaDefinition(childClass);
-        Preconditions.checkArgument(origSchema instanceof CaseSchemaNode, "Supplied schema %s is not case.", origSchema);
+        checkArgument(origSchema instanceof CaseSchemaNode, "Supplied schema %s is not case.", origSchema);
 
         /* FIXME: Make sure that if there are multiple augmentations of same
          * named case, with same structure we treat it as equals
@@ -276,37 +264,38 @@ public class BindingRuntimeContext implements Immutable {
      *     {@link DataSchemaNode}, {@link AugmentationSchemaNode} or {@link TypeDefinition}
      *     which was used to generate supplied class.
      */
-    public Entry<GeneratedType, Object> getTypeWithSchema(final Class<?> type) {
+    public Entry<GeneratedType, WithStatus> getTypeWithSchema(final Class<?> type) {
         return getTypeWithSchema(referencedType(type));
     }
 
-    public Entry<GeneratedType, Object> getTypeWithSchema(final String type) {
+    public Entry<GeneratedType, WithStatus> getTypeWithSchema(final String type) {
         return getTypeWithSchema(referencedType(type));
     }
 
-    private Entry<GeneratedType, Object> getTypeWithSchema(final Type referencedType) {
-        final Object schema = typeToDefiningSchema.get(referencedType);
-        Preconditions.checkNotNull(schema, "Failed to find schema for type %s", referencedType);
-
-        final Type definedType = typeToDefiningSchema.inverse().get(schema);
-        Preconditions.checkNotNull(definedType, "Failed to find defined type for %s schema %s", referencedType, schema);
+    private Entry<GeneratedType, WithStatus> getTypeWithSchema(final Type referencedType) {
+        final WithStatus schema = runtimeTypes.findSchema(referencedType).orElseThrow(
+            () -> new NullPointerException("Failed to find schema for type " + referencedType));
+        final Type definedType = runtimeTypes.findType(schema).orElseThrow(
+            () -> new NullPointerException("Failed to find defined type for " + referencedType + " schema " + schema));
 
         if (definedType instanceof GeneratedTypeBuilder) {
             return new SimpleEntry<>(((GeneratedTypeBuilder) definedType).toInstance(), schema);
         }
-        Preconditions.checkArgument(definedType instanceof GeneratedType,"Type {} is not GeneratedType", referencedType);
-        return new SimpleEntry<>((GeneratedType) definedType,schema);
+        checkArgument(definedType instanceof GeneratedType, "Type %s is not a GeneratedType", referencedType);
+        return new SimpleEntry<>((GeneratedType) definedType, schema);
     }
 
     public ImmutableMap<Type, Entry<Type, Type>> getChoiceCaseChildren(final DataNodeContainer schema) {
-        final Map<Type,Entry<Type,Type>> childToCase = new HashMap<>();
-        for (final ChoiceSchemaNode choice :  FluentIterable.from(schema.getChildNodes()).filter(ChoiceSchemaNode.class)) {
+        final Map<Type, Entry<Type, Type>> childToCase = new HashMap<>();
+
+        for (final ChoiceSchemaNode choice :  Iterables.filter(schema.getChildNodes(), ChoiceSchemaNode.class)) {
             final ChoiceSchemaNode originalChoice = getOriginalSchema(choice);
-            final Type choiceType = referencedType(typeToDefiningSchema.inverse().get(originalChoice));
-            final Collection<Type> cases = choiceToCases.get(choiceType);
+            final java.util.Optional<Type> optType = runtimeTypes.findType(originalChoice);
+            checkState(optType.isPresent(), "Failed to find generated type for choice %s", originalChoice);
+            final Type choiceType = optType.get();
 
-            for (Type caze : cases) {
-                final Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType,caze);
+            for (Type caze : runtimeTypes.findCases(referencedType(choiceType))) {
+                final Entry<Type,Type> caseIdentifier = new SimpleEntry<>(choiceType, caze);
                 final HashSet<Type> caseChildren = new HashSet<>();
                 if (caze instanceof GeneratedTypeBuilder) {
                     caze = ((GeneratedTypeBuilder) caze).toInstance();
@@ -327,7 +316,7 @@ public class BindingRuntimeContext implements Immutable {
      * @return mapped enum constants from yang with their corresponding values in generated binding classes
      */
     public BiMap<String, String> getEnumMapping(final Class<?> enumClass) {
-        final Entry<GeneratedType, Object> typeWithSchema = getTypeWithSchema(enumClass);
+        final Entry<GeneratedType, WithStatus> typeWithSchema = getTypeWithSchema(enumClass);
         return getEnumMapping(typeWithSchema);
     }
 
@@ -335,11 +324,11 @@ public class BindingRuntimeContext implements Immutable {
      * See {@link #getEnumMapping(Class)}}
      */
     public BiMap<String, String> getEnumMapping(final String enumClass) {
-        final Entry<GeneratedType, Object> typeWithSchema = getTypeWithSchema(enumClass);
+        final Entry<GeneratedType, WithStatus> typeWithSchema = getTypeWithSchema(enumClass);
         return getEnumMapping(typeWithSchema);
     }
 
-    private static BiMap<String, String> getEnumMapping(final Entry<GeneratedType, Object> typeWithSchema) {
+    private static BiMap<String, String> getEnumMapping(final Entry<GeneratedType, WithStatus> typeWithSchema) {
         final TypeDefinition<?> typeDef = (TypeDefinition<?>) typeWithSchema.getValue();
 
         Preconditions.checkArgument(typeDef instanceof EnumTypeDefinition);
@@ -356,7 +345,7 @@ public class BindingRuntimeContext implements Immutable {
     }
 
     public Set<Class<?>> getCases(final Class<?> choice) {
-        final Collection<Type> cazes = choiceToCases.get(referencedType(choice));
+        final Collection<Type> cazes = runtimeTypes.findCases(referencedType(choice));
         final Set<Class<?>> ret = new HashSet<>(cazes.size());
         for(final Type caze : cazes) {
             try {
@@ -371,16 +360,19 @@ public class BindingRuntimeContext implements Immutable {
 
     public Class<?> getClassForSchema(final SchemaNode childSchema) {
         final SchemaNode origSchema = getOriginalSchema(childSchema);
-        final Type clazzType = typeToDefiningSchema.inverse().get(origSchema);
+        final java.util.Optional<Type> clazzType = runtimeTypes.findType(origSchema);
+        checkArgument(clazzType.isPresent(), "Failed to find binding type for %s (original %s)",
+            childSchema, origSchema);
+
         try {
-            return strategy.loadClass(clazzType);
+            return strategy.loadClass(clazzType.get());
         } catch (final ClassNotFoundException e) {
             throw new IllegalStateException(e);
         }
     }
 
-    public ImmutableMap<AugmentationIdentifier,Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
-        final Map<AugmentationIdentifier,Type> identifierToType = new HashMap<>();
+    public ImmutableMap<AugmentationIdentifier, Type> getAvailableAugmentationTypes(final DataNodeContainer container) {
+        final Map<AugmentationIdentifier, Type> identifierToType = new HashMap<>();
         if (container instanceof AugmentationTarget) {
             final Set<AugmentationSchemaNode> augments = ((AugmentationTarget) container).getAvailableAugmentations();
             for (final AugmentationSchemaNode augment : augments) {
@@ -391,9 +383,9 @@ public class BindingRuntimeContext implements Immutable {
                 }
 
                 if (!augment.getChildNodes().isEmpty()) {
-                    final Type augType = typeToDefiningSchema.inverse().get(augOrig);
-                    if (augType != null) {
-                        identifierToType.put(getAugmentationIdentifier(augment),augType);
+                    final java.util.Optional<Type> augType = runtimeTypes.findType(augOrig);
+                    if (augType.isPresent()) {
+                        identifierToType.put(getAugmentationIdentifier(augment), augType.get());
                     }
                 }
             }
index b3f60616563612048922f02777745f8fe884b442..3cbf337f6c4ffe20e4200829fa728dcd45925c7f 100644 (file)
@@ -108,13 +108,13 @@ public final class TypeProviderImpl implements TypeProvider {
     /**
      * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
      */
-    private final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap;
+    private final Map<String, Map<Optional<Revision>, Map<String, Type>>> genTypeDefsContextMap = new HashMap<>();
 
     /**
      * The map which maps schema paths to JAVA <code>Type</code>.
      */
-    private final Map<SchemaPath, Type> referencedTypes;
-    private final Map<Module, Set<Type>> additionalTypes;
+    private final Map<SchemaPath, Type> referencedTypes = new HashMap<>();
+    private final Map<Module, Set<Type>> additionalTypes = new HashMap<>();
 
     /**
      * Creates new instance of class <code>TypeProviderImpl</code>.
@@ -128,9 +128,6 @@ public final class TypeProviderImpl implements TypeProvider {
         Preconditions.checkArgument(schemaContext != null, "Schema Context cannot be null!");
 
         this.schemaContext = schemaContext;
-        this.genTypeDefsContextMap = new HashMap<>();
-        this.referencedTypes = new HashMap<>();
-        this.additionalTypes = new HashMap<>();
         resolveTypeDefsFromContext();
     }