Switch to Objects.requireNonNull
[mdsal.git] / binding2 / mdsal-binding2-generator-impl / src / main / java / org / opendaylight / mdsal / binding / javav2 / generator / impl / GenHelperUtil.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.mdsal.binding.javav2.generator.impl;
10
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static java.util.Objects.requireNonNull;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createReturnTypeForUnion;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.getAugmentIdentifier;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.isInnerType;
19 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant;
20 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
21 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
22 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTypeBuilder;
23 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.computeDefaultSUID;
24 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
25 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
26 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.IDENTIFIABLE;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.IDENTIFIER;
28 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.NOTIFICATION;
29 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
30 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.wildcardTypeFor;
31 import static org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeGenHelper.resolveRegExpressions;
32 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
33
34 import com.google.common.annotations.Beta;
35 import com.google.common.base.Preconditions;
36
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.stream.Collectors;
43 import javax.annotation.Nullable;
44
45 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
46 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
47 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
48 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
49 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
50 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
51 import org.opendaylight.mdsal.binding.javav2.generator.util.ReferencedTypeImpl;
52 import org.opendaylight.mdsal.binding.javav2.generator.util.TypeComments;
53 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
54 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
55 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
56 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.BaseYangTypes;
57 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.GroupingDefinitionDependencySort;
58 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
59 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
60 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
61 import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
62 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
63 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
64 import org.opendaylight.mdsal.binding.javav2.model.api.YangSourceDefinition;
65 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
66 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
67 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
68 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
69 import org.opendaylight.mdsal.binding.javav2.spec.base.BaseIdentity;
70 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
71 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
72 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
73 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
74 import org.opendaylight.yangtools.yang.common.QName;
75 import org.opendaylight.yangtools.yang.model.api.AnyDataSchemaNode;
76 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
77 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
78 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
79 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
80 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
81 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
82 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
83 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
84 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
85 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
86 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
87 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
88 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
89 import org.opendaylight.yangtools.yang.model.api.Module;
90 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
91 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
92 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
93 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
94 import org.opendaylight.yangtools.yang.model.api.Status;
95 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
96 import org.opendaylight.yangtools.yang.model.api.UsesNode;
97 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
98 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
99 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
100 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
101 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
102 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
103
104 /**
105  * Helper util class used for generation of types in Binding spec v2.
106  */
107 @Beta
108 final class GenHelperUtil {
109
110     private GenHelperUtil() {
111         throw new UnsupportedOperationException("Util class");
112     }
113
114     /**
115      * Create GeneratedTypeBuilder object from module argument.
116      *
117      * @param module               Module object from which builder will be created
118      * @param genCtx               generated context
119      * @param verboseClassComments verbosity switch
120      * @return <code>GeneratedTypeBuilder</code> which is internal
121      *      representation of the module
122      * @throws IllegalArgumentException if module is null
123      */
124     static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx,
125         final boolean verboseClassComments) {
126         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
127
128         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments,
129                 genCtx.get(module));
130         addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
131         moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
132
133         if (verboseClassComments) {
134             YangSourceDefinition.of(module).ifPresent(moduleDataTypeBuilder::setYangSourceDefinition);
135             TypeComments.description(module).ifPresent(moduleDataTypeBuilder::addComment);
136             module.getDescription().ifPresent(moduleDataTypeBuilder::setDescription);
137             module.getReference().ifPresent(moduleDataTypeBuilder::setReference);
138         }
139
140         return moduleDataTypeBuilder;
141     }
142
143     /**
144      * Generates type builder for <code>module</code>.
145      *
146      * @param module               Module which is source of package name for generated type
147      *                             builder
148      * @param postfix              string which is added to the module class name representation
149      *                             as suffix
150      * @param verboseClassComments verbosity switch
151      * @return instance of GeneratedTypeBuilder which represents
152      * <code>module</code>.
153      * @throws IllegalArgumentException if <code>module</code> is null
154      */
155     static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
156             verboseClassComments, final ModuleContext context) {
157         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
158         final String packageName = BindingMapping.getRootPackageName(module);
159         // underscore used as separator for distinction of module name parts
160         final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
161
162         final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName, context);
163         if (verboseClassComments) {
164             YangSourceDefinition.of(module).ifPresent(moduleBuilder::setYangSourceDefinition);
165             TypeComments.description(module).ifPresent(moduleBuilder::addComment);
166             module.getDescription().ifPresent(moduleBuilder::setDescription);
167             module.getReference().ifPresent(moduleBuilder::setReference);
168         }
169         moduleBuilder.setModuleName(moduleName);
170         return moduleBuilder;
171     }
172
173     /**
174      * Adds the implemented types to type builder.
175      *
176      * <p>
177      * The method passes through the list of <i>uses</i> in
178      * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
179      * generated type from all groupings
180      * allGroupings} which is added as <i>implements type</i> to
181      * <code>builder</code>
182      *
183      * @param dataNodeContainer element which contains the list of used YANG groupings
184      * @param builder           builder to which are added implemented types according to
185      *                          <code>dataNodeContainer</code>
186      * @param genCtx            generated context
187      * @return generated type builder with all implemented types
188      */
189     static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
190                                                                 final GeneratedTypeBuilder builder, final Map<Module,
191             ModuleContext> genCtx) {
192         for (final UsesNode usesNode : dataNodeContainer.getUses()) {
193             final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
194             if (genType == null) {
195                 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
196                         + builder.getName());
197             }
198             builder.addImplementsType(genType);
199         }
200         return builder;
201     }
202
203     static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
204         for (final ModuleContext ctx : genCtx.values()) {
205             final GeneratedTypeBuilder result = ctx.getGrouping(path);
206             if (result != null) {
207                 return result;
208             }
209         }
210         return null;
211     }
212
213     static GeneratedTypeBuilder findIdentityByQname(final QName qname, final Map<Module, ModuleContext> genCtx) {
214         for (final ModuleContext ctx : genCtx.values()) {
215             final GeneratedTypeBuilder result = ctx.getIdentities().get(qname);
216             if (result != null) {
217                 return result;
218             }
219         }
220         return null;
221     }
222
223     /**
224      * Adds the methods to <code>typeBuilder</code> which represent subnodes of
225      * node for which <code>typeBuilder</code> was created.
226      *
227      * <p>
228      * The subnodes aren't mapped to the methods if they are part of grouping or
229      * augment (in this case are already part of them).
230      *
231      * @param module          current module
232      * @param basePackageName string contains the module package name
233      * @param parent          generated type builder which represents any node. The subnodes
234      *                        of this node are added to the <code>typeBuilder</code> as
235      *                        methods. The subnode can be of type leaf, leaf-list, list,
236      *                        container, choice.
237      * @param childOf         parent type
238      * @param schemaNodes     set of data schema nodes which are the children of the node
239      *      for which <code>typeBuilder</code> was created
240      * @return generated type builder which is the same builder as input
241      *      parameter. The getter methods (representing child nodes) could be
242      *      added to it.
243      */
244     static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
245                                                        final GeneratedTypeBuilder parent, final GeneratedTypeBuilder
246                                                                childOf,
247                                                        final Iterable<DataSchemaNode> schemaNodes, final Map<Module,
248             ModuleContext> genCtx,
249                                                        final SchemaContext schemaContext, final boolean
250                                                                verboseClassComments,
251                                                        final Map<String, Map<String, GeneratedTypeBuilder>>
252                                                                genTypeBuilders,
253                                                        final TypeProvider typeProvider, final BindingNamespaceType
254                                                                namespaceType) {
255
256         if (schemaNodes != null && parent != null) {
257             for (final DataSchemaNode schemaNode : schemaNodes) {
258                 if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
259                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
260                             schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
261                 }
262             }
263         }
264         return parent;
265     }
266
267     static boolean resolveDataSchemaNodesCheck(final Module module, final SchemaContext schemaContext,
268                                                final DataSchemaNode schemaNode) {
269         if (!schemaNode.isAugmenting()) {
270             return true;
271         }
272
273         final QName qname = schemaNode.getPath().getLastComponent();
274         final Module originalModule = schemaContext.findModule(qname.getModule()).get();
275         return module.equals(originalModule);
276     }
277
278     private static QName createQNameFromSuperNode(final Module module, final Object node, final SchemaNode
279             superChildNode) {
280         QName childNodeQName = null;
281         if (node instanceof Module) {
282             childNodeQName = QName.create(((Module) node).getQNameModule(), superChildNode.getQName().getLocalName());
283         } else if (node instanceof SchemaNode) {
284             childNodeQName = QName.create(((SchemaNode) node).getQName(), superChildNode.getQName().getLocalName());
285         } else if (node instanceof AugmentationSchemaNode) {
286             childNodeQName = QName.create(module.getQNameModule(), superChildNode.getQName().getLocalName());
287         } else {
288             throw new IllegalArgumentException("Not support node type:" + node);
289         }
290
291         return childNodeQName;
292     }
293
294     private static void addUsesImplements(final SchemaNode superNode, final Module superModule,
295                                           final Object node, final Module module, final SchemaContext schemaContext,
296                                           final Map<Module, ModuleContext> genCtx, final BindingNamespaceType
297                                                   namespaceType) {
298         if (superNode instanceof DataNodeContainer) {
299             for (DataSchemaNode superChildNode : ((DataNodeContainer) superNode).getChildNodes()) {
300                 if (superChildNode instanceof DataNodeContainer || superChildNode instanceof ChoiceSchemaNode) {
301                     final QName childQName = createQNameFromSuperNode(module, node, superChildNode);
302                     DataSchemaNode childNode = ((DataNodeContainer) node).getDataChildByName(childQName);
303                     requireNonNull(childNode, () -> node + "->" + childQName);
304
305                     final GeneratedTypeBuilder type = genCtx.get(module).getChildNode(childNode.getPath());
306                     final GeneratedTypeBuilder superType = genCtx.get(superModule).getChildNode(superChildNode
307                             .getPath());
308
309                     requireNonNull(type, () -> module + "->" + childNode.getPath());
310                     requireNonNull(superType, () -> superModule + "->" + superChildNode.getPath());
311                     type.addImplementsType(superType);
312                     if (superChildNode instanceof ListSchemaNode
313                             && !((ListSchemaNode) superChildNode).getKeyDefinition().isEmpty()) {
314                         if (BindingNamespaceType.isGrouping(namespaceType)) {
315                             genCtx.get(module).getKeyType(childNode.getPath())
316                                     .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
317                         } else if (BindingNamespaceType.isData(namespaceType)) {
318                             genCtx.get(module).getKeyGenTO(childNode.getPath())
319                                     .addImplementsType(genCtx.get(superModule).getKeyType(superChildNode.getPath()));
320                         }
321                     }
322                     addUsesImplements(superChildNode, superModule, childNode, module, schemaContext, genCtx,
323                             namespaceType);
324                 }
325             }
326         } else if (superNode instanceof ChoiceSchemaNode) {
327             for (CaseSchemaNode superCaseNode : ((ChoiceSchemaNode) superNode).getCases().values()) {
328                 final QName childQName = createQNameFromSuperNode(module, node, superCaseNode);
329                 CaseSchemaNode caseNode = ((ChoiceSchemaNode) node).getCaseNodeByName(childQName);
330                 requireNonNull(caseNode, () -> node + "->" + childQName);
331
332                 final GeneratedTypeBuilder type = genCtx.get(module).getCase(caseNode.getPath());
333                 final GeneratedTypeBuilder superType = genCtx.get(superModule).getCase(superCaseNode.getPath());
334                 requireNonNull(type, () -> module + "->" + caseNode.getPath());
335                 requireNonNull(superType, () -> superModule + "->" + superCaseNode.getPath());
336                 type.addImplementsType(superType);
337                 addUsesImplements(superCaseNode, superModule, caseNode, module, schemaContext, genCtx, namespaceType);
338             }
339         } else {
340             throw new IllegalArgumentException("Not support super node :" + superNode);
341         }
342     }
343
344     private static GroupingDefinition findGroupingNodeFromUses(final Module module, final SchemaContext schemaContext,
345                                                                final Object parentNode, final UsesNode usesNode) {
346         SchemaNode groupingNode;
347         if (parentNode instanceof Module) {
348             final Module superModule = schemaContext.findModule(
349                     usesNode.getGroupingPath().getLastComponent().getModule()).get();
350             groupingNode = superModule.getGroupings()
351                     .stream().filter(grouping -> grouping.getPath().equals(usesNode.getGroupingPath()))
352                     .findFirst().orElse(null);
353         } else {
354             //FIXME: Schema path is not unique for Yang 1.1, findDataSchemaNode always does search from data node first.
355             final Iterable<QName> prefixedPath = usesNode.getGroupingPath().getPathFromRoot();
356             final QName current = prefixedPath.iterator().next();
357             final Module targetModule = schemaContext.findModule(current.getModule()).orElse(null);
358             Preconditions.checkArgument(targetModule != null, "Cannot find target module for %s and %s.",
359                     current.getNamespace(), current.getRevision());
360             groupingNode = targetModule.getGroupings().stream()
361                     .filter(grouping -> grouping.getPath().equals(usesNode.getGroupingPath()))
362                     .collect(Collectors.toList()).get(0);
363             if (groupingNode == null) {
364                 groupingNode = SchemaContextUtil.findDataSchemaNode(schemaContext, usesNode.getGroupingPath());
365             }
366         }
367
368         requireNonNull(groupingNode, () -> module + "->" + usesNode.getGroupingPath());
369         Preconditions.checkState(groupingNode instanceof GroupingDefinition, "%s->%s", module,
370                 usesNode.getGroupingPath());
371         return (GroupingDefinition) groupingNode;
372     }
373
374     static Map<Module, ModuleContext> processUsesImplements(final Object node, final Module module,
375                                                             final SchemaContext schemaContext, final Map<Module,
376             ModuleContext> genCtx, final BindingNamespaceType namespaceType) {
377         if (node instanceof DataNodeContainer) {
378             for (final UsesNode usesNode : ((DataNodeContainer) node).getUses()) {
379                 final GroupingDefinition grouping = findGroupingNodeFromUses(module, schemaContext, node, usesNode);
380                 final Module superModule = SchemaContextUtil.findParentModule(schemaContext, grouping);
381                 addUsesImplements(grouping, superModule, node, module, schemaContext, genCtx, namespaceType);
382             }
383         }
384         return genCtx;
385     }
386
387     static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
388         for (final ModuleContext ctx : genCtx.values()) {
389             final GeneratedTypeBuilder result = ctx.getChildNode(path);
390             if (result != null) {
391                 return result;
392             }
393         }
394         return null;
395     }
396
397     static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
398         for (final ModuleContext ctx : genCtx.values()) {
399             final GeneratedTypeBuilder result = ctx.getCase(path);
400             if (result != null) {
401                 return result;
402             }
403         }
404         return null;
405     }
406
407     static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module,
408             final String augmentPackageName, final GeneratedTypeBuilder targetTypeBuilder, final SchemaNode targetNode,
409             final List<AugmentationSchemaNode> schemaPathAugmentListEntry, final Map<String, Map<String,
410                  GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
411             final SchemaContext schemaContext, final boolean verboseClassComments, final TypeProvider typeProvider,
412             final BindingNamespaceType namespaceType) {
413
414         //pick augmentation grouped by augmentation target, there is always at least one
415         final AugmentationSchemaNode augSchema = schemaPathAugmentListEntry.get(0);
416
417         //this requires valid semantics in YANG model
418         String augIdentifier = null;
419         for (AugmentationSchemaNode aug : schemaPathAugmentListEntry) {
420             // FIXME: when there're multiple augment identifiers for augmentations of same target,
421             // it would pick the first identifier.
422             augIdentifier = getAugmentIdentifier(aug.getUnknownSchemaNodes());
423             break;
424         }
425
426         if (augIdentifier == null) {
427             augIdentifier = new StringBuilder(module.getName())
428                     .append('_').append(targetNode.getQName().getLocalName()).toString();
429         }
430
431         GeneratedTypeBuilderImpl augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier,
432                 true, false, genCtx.get(module));
433
434         augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
435         augTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, augTypeBuilder));
436         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeBuilder.toInstance()));
437         augTypeBuilder.setBasePackageName(BindingMapping.getRootPackageName(module));
438         augTypeBuilder.setWithBuilder(true);
439         augTypeBuilder.setBindingNamespaceType(namespaceType);
440         annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
441
442         //If target is case node then pass down parent type (the closest ancestor) to children data nodes.
443         final GeneratedTypeBuilder childOf;
444         if (targetNode instanceof CaseSchemaNode) {
445             childOf = (GeneratedTypeBuilder) targetTypeBuilder.getParentTypeForBuilder();
446         } else {
447             augTypeBuilder.setParentTypeForBuilder(targetTypeBuilder);
448             childOf = targetTypeBuilder;
449         }
450
451         //produces getters for augTypeBuilder eventually
452         for (AugmentationSchemaNode aug : schemaPathAugmentListEntry) {
453             //apply all uses
454             addImplementedInterfaceFromUses(aug, augTypeBuilder, genCtx);
455             augSchemaNodeToMethods(module, BindingMapping.getRootPackageName(module), augTypeBuilder, childOf,
456                     aug.getChildNodes(), genCtx, schemaContext, verboseClassComments, typeProvider, genTypeBuilders,
457                     targetTypeBuilder.getBindingNamespaceType());
458         }
459
460         final Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.computeIfAbsent(
461                 augmentPackageName, k -> new HashMap<>());
462
463         augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
464
465         if (!augSchema.getChildNodes().isEmpty()) {
466             genCtx.get(module).addTargetToAugmentation(augTypeBuilder, augSchema.getTargetPath());
467         }
468         genCtx.get(module).addAugmentType(augTypeBuilder);
469         genCtx.get(module).addTypeToAugmentations(augTypeBuilder, schemaPathAugmentListEntry);
470         return genCtx;
471     }
472
473     /**
474      * Adds the methods to <code>typeBuilder</code> what represents subnodes of
475      * node for which <code>typeBuilder</code> was created.
476      *
477      * @param module          current module
478      * @param basePackageName string contains the module package name
479      * @param typeBuilder     generated type builder which represents any node. The subnodes
480      *                        of this node are added to the <code>typeBuilder</code> as
481      *                        methods. The subnode can be of type leaf, leaf-list, list,
482      *                        container, choice.
483      * @param childOf         parent type
484      * @param schemaNodes     set of data schema nodes which are the children of the node
485      *                        for which <code>typeBuilder</code> was created
486      * @return generated type builder which is the same object as the input added to it.
487      */
488     private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
489                                                                final GeneratedTypeBuilder typeBuilder, final
490                                                                GeneratedTypeBuilder childOf, final
491                                                                Iterable<DataSchemaNode> schemaNodes,
492                                                                final Map<Module, ModuleContext> genCtx, final
493                                                                SchemaContext schemaContext, final boolean
494                                                                        verboseClassComments, final TypeProvider
495                                                                        typeProvider, final Map<String, Map<String,
496             GeneratedTypeBuilder>> genTypeBuilders, final BindingNamespaceType namespaceType) {
497         if (schemaNodes != null && typeBuilder != null) {
498             for (final DataSchemaNode schemaNode : schemaNodes) {
499                 if (!schemaNode.isAugmenting()) {
500                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module, genCtx,
501                             schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
502                 }
503             }
504         }
505         return typeBuilder;
506     }
507
508     /**
509      * Instantiates generated type builder with <code>packageName</code> and
510      * <code>schemaNode</code>.
511      *
512      * <p>
513      * The new builder always implements
514      * {@link TreeNode TreeNode}.<br>
515      * If <code>schemaNode</code> is instance of GroupingDefinition it also
516      * implements {@link Augmentable
517      * Augmentable}.<br>
518      * If <code>schemaNode</code> is instance of
519      * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
520      * DataNodeContainer} it can also implement nodes which are specified in
521      * <i>uses</i>.
522      *
523      * @param basePackageName string contains the module package name
524      * @param schemaNode      schema node for which is created generated type builder
525      * @param childOf         parent generated type of data tree node, which should be
526      *                        set null if current schema node is not a data tree node.
527      * @param schemaContext   schema context
528      * @return generated type builder <code>schemaNode</code>
529      */
530     public static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String basePackageName, final SchemaNode
531             schemaNode, @Nullable final Type childOf, final Module module, final Map<Module, ModuleContext> genCtx,
532                                                                      final SchemaContext schemaContext, final boolean
533                                                                              verboseClassComments, final Map<String,
534             Map<String,
535                     GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType
536                                                                              namespaceType) {
537
538         GeneratedTypeBuilder it = addRawInterfaceDefinition(basePackageName, schemaNode, schemaContext, "", "",
539                 verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
540         if (BindingNamespaceType.isData(namespaceType)) {
541             if (childOf == null) {
542                 it.addImplementsType(BindingTypes.TREE_NODE);
543             } else {
544                 if (!(schemaNode instanceof ListSchemaNode)
545                         || ((ListSchemaNode) schemaNode).getKeyDefinition().isEmpty()) {
546                     it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, childOf,
547                             parameterizedTypeFor(BindingTypes.ITEM, it)));
548                 }
549             }
550
551             if (!(schemaNode instanceof CaseSchemaNode)) {
552                 it.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, it));
553             }
554
555             it.addImplementsType(BindingTypes.augmentable(it));
556         }
557
558         if (schemaNode instanceof DataNodeContainer) {
559             groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings(), genCtx, schemaContext,
560                     verboseClassComments, genTypeBuilders, typeProvider);
561             it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
562         }
563
564         return it;
565     }
566
567     static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, final String
568             parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
569                                                     final SchemaContext schemaContext, final boolean
570                                                             verboseClassComments, final Map<String, Map<String,
571             GeneratedTypeBuilder>>
572                                                             genTypeBuilders, final TypeProvider typeProvider, final
573                                                     Map<Module, ModuleContext> genCtx) {
574         final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition(basePackageName, notification,
575                 null, module, genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider,
576                 BindingNamespaceType.Notification);
577         annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
578         notificationInterface.addImplementsType(NOTIFICATION);
579         genCtx.get(module).addChildNodeType(notification, notificationInterface);
580
581         // Notification object
582         resolveDataSchemaNodes(module, basePackageName, notificationInterface,
583                 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
584                 verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Notification);
585
586         //in case of tied notification, incorporate parent's localName
587         final StringBuilder sb = new StringBuilder("on_");
588         if (parentName != null) {
589             sb.append(parentName).append('_');
590         }
591         sb.append(notificationInterface.getName());
592
593         listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(),
594                 JavaIdentifier.METHOD))
595                 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
596                 .setComment(encodeAngleBrackets(notification.getDescription().orElse(null))).setReturnType(Types.VOID);
597         return listenerInterface;
598     }
599
600     /**
601      * Returns reference to generated type builder for specified
602      * <code>schemaNode</code> with <code>packageName</code>.
603      *
604      * <p>
605      * Firstly the generated type builder is searched in
606      * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
607      * found it is created and added to <code>genTypeBuilders</code>.
608      *
609      * @param basePackageName string contains the module package name
610      * @param schemaNode      schema node which provide data about the schema node name
611      * @param schemaContext   schema context
612      * @param prefix          return type name prefix
613      * @return generated type builder for <code>schemaNode</code>
614      * @throws IllegalArgumentException <ul>
615      *                                  <li>if <code>schemaNode</code> is null</li>
616      *                                  <li>if <code>packageName</code> is null</li>
617      *                                  <li>if QName of schema node is null</li>
618      *                                  <li>if schemaNode name is null</li>
619      *                                  </ul>
620      */
621     static GeneratedTypeBuilder addRawInterfaceDefinition(final String basePackageName, final SchemaNode schemaNode,
622                                                           final SchemaContext schemaContext, final String prefix,
623                                                           final String suffix,
624                                                           final boolean verboseClassComments, final Map<String,
625             Map<String, GeneratedTypeBuilder>> genTypeBuilders,
626                                                           final BindingNamespaceType namespaceType, final
627                                                           ModuleContext context) {
628
629         Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
630         Preconditions.checkArgument(basePackageName != null, "Base package Name for Generated Type cannot be NULL.");
631         String schemaNodeName = schemaNode.getQName().getLocalName();
632         Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
633
634         if (prefix != null && !prefix.isEmpty()) {
635             // underscore used as separator for distinction of class name parts
636             schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
637         }
638
639         if (suffix != null && !suffix.isEmpty()) {
640             // underscore used as separator for distinction of class name parts
641             schemaNodeName = new StringBuilder(schemaNodeName).append('_').append(suffix).toString();
642         }
643
644         final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath(), namespaceType);
645         final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName, context);
646         final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
647         qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
648         if (verboseClassComments) {
649             YangSourceDefinition.of(module, schemaNode).ifPresent(newType::setYangSourceDefinition);
650             TypeComments.description(schemaNode).ifPresent(newType::addComment);
651             schemaNode.getDescription().ifPresent(newType::setDescription);
652             schemaNode.getReference().ifPresent(newType::setReference);
653         }
654         newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
655         newType.setModuleName(module.getName());
656         newType.setBasePackageName(BindingMapping.getRootPackageName(module));
657         newType.setWithBuilder(AuxiliaryGenUtils.hasBuilderClass(schemaNode, namespaceType));
658         newType.setBindingNamespaceType(namespaceType);
659
660         if (!genTypeBuilders.containsKey(packageName)) {
661             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
662             builders.put(newType.getName(), newType);
663             genTypeBuilders.put(packageName, builders);
664         } else {
665             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
666             if (!builders.containsKey(newType.getName())) {
667                 builders.put(newType.getName(), newType);
668             }
669         }
670         return newType;
671
672     }
673
674     private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
675                                                        final GeneratedTypeBuilder typeBuilder, final
676                                                        GeneratedTypeBuilder childOf, final Module module,
677                                                        final Map<Module, ModuleContext> genCtx, final SchemaContext
678                                                                schemaContext, final boolean verboseClassComments,
679                                                        final Map<String, Map<String, GeneratedTypeBuilder>>
680                                                                genTypeBuilders, final TypeProvider typeProvider,
681                                                        final BindingNamespaceType namespaceType) {
682
683         if (node != null && typeBuilder != null) {
684             if (node instanceof ContainerSchemaNode) {
685                 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
686                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
687             } else if (node instanceof LeafListSchemaNode) {
688                 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) node, module,
689                         typeProvider, genCtx, verboseClassComments);
690             } else if (node instanceof LeafSchemaNode) {
691                 resolveLeafSchemaNodeAsMethod("", schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
692                         typeProvider, verboseClassComments);
693             } else if (node instanceof ListSchemaNode) {
694                 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
695                         verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
696             } else if (node instanceof ChoiceSchemaNode) {
697                 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, childOf,
698                         (ChoiceSchemaNode) node, genTypeBuilders, genCtx, typeProvider, namespaceType);
699             } else if (node instanceof AnyXmlSchemaNode || node instanceof AnyDataSchemaNode) {
700                 resolveAnyNodeAsMethod(schemaContext, typeBuilder, genCtx, node, module, typeProvider);
701             }
702         }
703     }
704
705     /**
706      * Converts <code>choiceNode</code> to the list of generated types for
707      * choice and its cases.
708      *
709      * <p>
710      * The package names for choice and for its cases are created as
711      * concatenation of the module package (<code>basePackageName</code>) and
712      * names of all parents node.
713      *
714      * @param module          current module
715      * @param basePackageName string with the module package name
716      * @param parent          parent type
717      * @param choiceNode      choice node which is mapped to generated type. Also child
718      *                        nodes - cases are mapped to generated types.
719      * @throws IllegalArgumentException <ul>
720      *                                  <li>if <code>basePackageName</code> is null</li>
721      *                                  <li>if <code>choiceNode</code> is null</li>
722      *                                  </ul>
723      */
724     private static void choiceToGenType(final Module module, final SchemaContext schemaContext, final boolean
725             verboseClasssComments, final String basePackageName, final GeneratedTypeBuilder parent,
726                                         final GeneratedTypeBuilder childOf, final ChoiceSchemaNode choiceNode,
727                                         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
728                                         final Map<Module, ModuleContext> genCtx, final TypeProvider typeProvider,
729                                         final BindingNamespaceType namespaceType) {
730         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
731         checkArgument(choiceNode != null, "Choice Schema Node cannot be NULL.");
732
733         final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(basePackageName, choiceNode,
734                 schemaContext, "", "", verboseClasssComments, genTypeBuilders, namespaceType, genCtx.get(module));
735         constructGetter(parent, choiceNode.getQName().getLocalName(),
736                 choiceNode.getDescription().orElse(null), choiceTypeBuilder, choiceNode.getStatus());
737         choiceTypeBuilder.setParentTypeForBuilder(childOf);
738         if (BindingNamespaceType.isData(namespaceType)) {
739             choiceTypeBuilder.addImplementsType(parameterizedTypeFor(BindingTypes.INSTANTIABLE, choiceTypeBuilder));
740         }
741         annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
742         genCtx.get(module).addChildNodeType(choiceNode, choiceTypeBuilder);
743         generateTypesFromChoiceCases(module, schemaContext, genCtx, basePackageName, choiceTypeBuilder.toInstance(),
744                 choiceNode, verboseClasssComments, typeProvider, genTypeBuilders, namespaceType);
745     }
746
747     private static void containerToGenType(final Module module, final String basePackageName,
748                                            final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
749                                            final ContainerSchemaNode node,
750                                            final SchemaContext schemaContext, final boolean verboseClassComments,
751                                            final Map<Module, ModuleContext> genCtx,
752                                            final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
753                                            final TypeProvider typeProvider,
754                                            final BindingNamespaceType namespaceType) {
755
756         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
757                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
758         if (genType != null) {
759             StringBuilder getterName = new StringBuilder(node.getQName().getLocalName());
760             constructGetter(parent, getterName.toString(), node.getDescription().orElse(null), genType, node
761                     .getStatus());
762             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
763                     schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
764             processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
765         }
766     }
767
768     private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
769             parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
770                                       final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
771                                       final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final
772                                       TypeProvider typeProvider,
773                                       final BindingNamespaceType namespaceType) {
774
775         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
776                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
777         if (genType != null) {
778             final String nodeName = node.getQName().getLocalName();
779
780             Type getterReturnType = Types.listTypeFor(genType);
781             if (BindingNamespaceType.isGrouping(namespaceType)) {
782                 getterReturnType = Types.listTypeFor(wildcardTypeFor(genType.getPackageName(), genType.getName(),
783                         true, true, null));
784             }
785             constructGetter(parent, nodeName, node.getDescription().orElse(null), getterReturnType, node.getStatus());
786
787             final List<QName> listKeys = node.getKeyDefinition();
788             final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
789                     BindingNamespaceType.Key)).append('.').append(nodeName).toString();
790             //FIXME: Is it neccessary to generate interface of key and implemented by class?
791             if (BindingNamespaceType.isGrouping(namespaceType)) {
792                 final GeneratedTypeBuilder genTypeBuilder = resolveListKeyTypeBuilder(packageName, node,
793                         genCtx.get(module));
794                 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
795                     if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
796                         addSchemaNodeToListTypeBuilders(nodeName, basePackageName, schemaNode, genType,
797                                 genTypeBuilder, listKeys,
798                                 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments,
799                                 namespaceType);
800                     }
801                 }
802                 if (genTypeBuilder != null) {
803                     typeBuildersToGenTypes(module, genType, genTypeBuilder.toInstance(), genCtx, namespaceType);
804                     genCtx.get(module).addKeyType(node.getPath(), genTypeBuilder);
805                 }
806                 processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
807             } else {
808                 final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node, genCtx.get(module));
809                 if (genTOBuilder != null) {
810                     final Type identifiableMarker = Types.parameterizedTypeFor(IDENTIFIABLE, genTOBuilder);
811                     genTOBuilder.addImplementsType(IDENTIFIER);
812                     genType.addImplementsType(identifiableMarker);
813                     if (BindingNamespaceType.isData(namespaceType)) {
814                         genType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, childOf,
815                                 parameterizedTypeFor(BindingTypes.IDENTIFIABLE_ITEM, genType, genTOBuilder)));
816                     }
817                 }
818
819                 for (final DataSchemaNode schemaNode : node.getChildNodes()) {
820                     if (resolveDataSchemaNodesCheck(module, schemaContext, schemaNode)) {
821                         addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder,
822                                 listKeys,
823                                 module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments,
824                                 namespaceType);
825                     }
826                 }
827                 processUsesImplements(node, module, schemaContext, genCtx, namespaceType);
828
829                 // serialVersionUID
830                 if (genTOBuilder != null) {
831                     final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
832                     prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
833                     genTOBuilder.setSUID(prop);
834                     typeBuildersToGenTypes(module, genType, genTOBuilder.toInstance(), genCtx, namespaceType);
835                     genCtx.get(module).addGeneratedTOBuilder(node.getPath(), genTOBuilder);
836                 }
837             }
838         }
839     }
840
841     private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
842                                                final Type keyType, final Map<Module, ModuleContext> genCtx,
843                                                final BindingNamespaceType namespaceType) {
844         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
845         if (keyType != null) {
846             Type returnKeyType = keyType;
847             if (BindingNamespaceType.isGrouping(namespaceType)) {
848                 returnKeyType = wildcardTypeFor(keyType.getPackageName(), keyType.getName(),
849                         true, true, null);
850             }
851             constructGetter(typeBuilder, "identifier", "Returns Primary Key of Yang List Type", returnKeyType, Status
852                     .CURRENT);
853
854         }
855     }
856
857     private static void addPatternConstant(final GeneratedTypeBuilder typeBuilder, final String leafName,
858                                            final List<PatternConstraint> patternConstraints) {
859         if (!patternConstraints.isEmpty()) {
860             final StringBuilder field = new StringBuilder();
861             field.append(BindingMapping.PATTERN_CONSTANT_NAME).append("_")
862                     .append(JavaIdentifierNormalizer.normalizeSpecificIdentifier(leafName, JavaIdentifier.METHOD));
863             typeBuilder.addConstant(Types.listTypeFor(BaseYangTypes.STRING_TYPE), field.toString(),
864                     resolveRegExpressions(patternConstraints));
865         }
866     }
867
868     /**
869      * Converts <code>leaf</code> to the getter method which is added to
870      * <code>typeBuilder</code>.
871      *
872      * @param typeBuilder generated type builder to which is added getter method as
873      *                    <code>leaf</code> mapping
874      * @param leaf        leaf schema node which is mapped as getter method which is
875      *                    added to <code>typeBuilder</code>
876      * @param module      Module in which type was defined
877      * @return boolean value
878      * <ul>
879      * <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
880      * null</li>
881      * <li>true - in other cases</li>
882      * </ul>
883      */
884     private static Type resolveLeafSchemaNodeAsMethod(final String nodeName, final SchemaContext schemaContext,
885                                                       final GeneratedTypeBuilder typeBuilder, final Map<Module,
886             ModuleContext> genCtx, final LeafSchemaNode leaf,
887                                                       final Module module, final TypeProvider typeProvider, final
888                                                       boolean verboseClassComments) {
889         if (leaf == null || typeBuilder == null) {
890             return null;
891         }
892
893         final String leafName = leaf.getQName().getLocalName();
894         if (leafName == null) {
895             return null;
896         }
897
898         final Module parentModule = findParentModule(schemaContext, leaf);
899         Type returnType = null;
900
901         final TypeDefinition<?> typeDef = leaf.getType();
902
903         if (leaf.isAddedByUses()) {
904             Preconditions.checkState(leaf instanceof DerivableSchemaNode);
905             if (isInnerType(leaf, typeDef)) {
906                 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
907                 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
908                         restrictions, genCtx.get(module));
909             } else {
910                 if (typeDef.getBaseType() == null && (typeDef instanceof EnumTypeDefinition
911                         || typeDef instanceof UnionTypeDefinition || typeDef instanceof BitsTypeDefinition)) {
912                     LeafSchemaNode originalLeaf = (LeafSchemaNode) ((DerivableSchemaNode) leaf).getOriginal()
913                             .orElse(null);
914                     requireNonNull(originalLeaf);
915                     returnType = genCtx.get(findParentModule(schemaContext, originalLeaf)).getInnerType(typeDef
916                             .getPath());
917                 } else {
918                     final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
919                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions,
920                             genCtx.get(module));
921                 }
922             }
923         } else if (isInnerType(leaf, typeDef)) {
924             if (typeDef instanceof EnumTypeDefinition) {
925                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, genCtx.get(module));
926                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
927                 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
928                         genCtx, typeBuilder, module);
929                 if (enumBuilder != null) {
930                     returnType = enumBuilder.toInstance(typeBuilder);
931                 }
932                 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
933             } else if (typeDef instanceof UnionTypeDefinition) {
934                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
935                         typeProvider, schemaContext, genCtx.get(module), genCtx);
936                 if (genTOBuilder != null) {
937                     //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
938                     returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule,
939                             typeProvider, verboseClassComments);
940                 }
941             } else if (typeDef instanceof BitsTypeDefinition) {
942                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
943                         typeProvider, schemaContext, genCtx.get(module), genCtx);
944                 if (genTOBuilder != null) {
945                     returnType = genTOBuilder.toInstance();
946                 }
947             } else {
948                 // It is constrained version of already declared type (inner declared type exists,
949                 // onlyfor special cases (Enum, Union, Bits), which were already checked.
950                 // In order to get proper class we need to look up closest derived type
951                 // and apply restrictions from leaf type
952                 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
953                 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
954                         restrictions, genCtx.get(module));
955                 addPatternConstant(typeBuilder, leafName, restrictions.getPatternConstraints());
956             }
957         } else {
958             final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
959             returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions, genCtx.get(module));
960             addPatternConstant(typeBuilder, leafName, restrictions.getPatternConstraints());
961         }
962
963         if (returnType == null) {
964             return null;
965         }
966
967         if (typeDef instanceof EnumTypeDefinition) {
968             ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
969         }
970
971         final String leafGetterName;
972         if ("key".equals(leafName.toLowerCase())) {
973             StringBuilder sb = new StringBuilder(leafName)
974                     .append('_').append("RESERVED_WORD");
975             leafGetterName = sb.toString();
976         } else {
977             leafGetterName = leafName;
978         }
979         constructGetter(typeBuilder, leafGetterName, leaf.getDescription().orElse(""), returnType, leaf.getStatus());
980         return returnType;
981     }
982
983     /**
984      * Converts <code>node</code> leaf list schema node to getter method of
985      * <code>typeBuilder</code>.
986      *
987      * @param typeBuilder  generated type builder to which is <code>node</code> added as
988      *                     getter method
989      * @param node         leaf list schema node which is added to
990      *                     <code>typeBuilder</code> as getter method
991      * @param module       module
992      * @param typeProvider type provider instance
993      * @param genCtx       actual generated context
994      * @return boolean value
995      * <ul>
996      * <li>true - if <code>node</code>, <code>typeBuilder</code>,
997      * nodeName equal null or <code>node</code> is added by <i>uses</i></li>
998      * <li>false - other cases</li>
999      * </ul>
1000      */
1001     private static boolean resolveLeafListSchemaNode(final SchemaContext schemaContext, final GeneratedTypeBuilder
1002             typeBuilder, final LeafListSchemaNode node, final Module module, final TypeProvider typeProvider,
1003                                                      final Map<Module, ModuleContext> genCtx, final boolean
1004                                                              verboseClassComments) {
1005         if (node == null || typeBuilder == null) {
1006             return false;
1007         }
1008
1009         final QName nodeName = node.getQName();
1010
1011         final TypeDefinition<?> typeDef = node.getType();
1012         final Module parentModule = findParentModule(schemaContext, node);
1013
1014         Type returnType = null;
1015         if (typeDef.getBaseType() == null) {
1016             if (typeDef instanceof EnumTypeDefinition) {
1017                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, genCtx.get(module));
1018                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
1019                 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName,
1020                         genCtx, typeBuilder, module);
1021                 returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName(), true,
1022                         null);
1023                 ((TypeProviderImpl) typeProvider).putReferencedType(node.getPath(), returnType);
1024             } else if (typeDef instanceof UnionTypeDefinition) {
1025                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule,
1026                         typeProvider, schemaContext, genCtx.get(module), genCtx);
1027                 if (genTOBuilder != null) {
1028                     returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule,
1029                             typeProvider, verboseClassComments);
1030                 }
1031             } else if (typeDef instanceof BitsTypeDefinition) {
1032                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, node, parentModule,
1033                         typeProvider, schemaContext, genCtx.get(module), genCtx);
1034                 returnType = genTOBuilder.toInstance();
1035             } else {
1036                 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
1037                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions,
1038                         genCtx.get(module));
1039
1040                 addPatternConstant(typeBuilder, nodeName.getLocalName(), restrictions.getPatternConstraints());
1041             }
1042         } else {
1043             final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
1044             returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions, genCtx.get(module));
1045
1046             addPatternConstant(typeBuilder, nodeName.getLocalName(), restrictions.getPatternConstraints());
1047         }
1048
1049         final ParameterizedType listType = Types.listTypeFor(returnType);
1050         constructGetter(typeBuilder, nodeName.getLocalName(), node.getDescription().orElse(null), listType, node
1051                 .getStatus());
1052         return true;
1053     }
1054
1055     /**
1056      * Converts <code>caseNodes</code> set to list of corresponding generated
1057      * types.
1058      *
1059      * <p>
1060      * For every <i>case</i> which isn't added through augment or <i>uses</i> is
1061      * created generated type builder. The package names for the builder is
1062      * created as concatenation of the module package (
1063      * <code>basePackageName</code>) and names of all parents nodes of the
1064      * concrete <i>case</i>. There is also relation "<i>implements type</i>"
1065      * between every case builder and <i>choice</i> type
1066      *
1067      * @param module               current module
1068      * @param schemaContext        current schema context
1069      * @param genCtx               actual generated context
1070      * @param basePackageName      string with the module package name
1071      * @param refChoiceType        type which represents superior <i>case</i>
1072      * @param choiceNode           choice case node which is mapped to generated type
1073      * @param verboseClassComments Javadoc verbosity switch
1074      * @throws IllegalArgumentException <ul>
1075      *                                  <li>if <code>basePackageName</code> equals null</li>
1076      *                                  <li>if <code>refChoiceType</code> equals null</li>
1077      *                                  <li>if <code>caseNodes</code> equals null</li>
1078      *                                  </ul>
1079      */
1080     private static void generateTypesFromChoiceCases(final Module module, final SchemaContext schemaContext,
1081                                                      final Map<Module, ModuleContext> genCtx, final String
1082                                                              basePackageName, final GeneratedType refChoiceType,
1083                                                      final ChoiceSchemaNode choiceNode, final boolean
1084                                                              verboseClassComments,
1085                                                      final TypeProvider typeProvider, final Map<String, Map<String,
1086             GeneratedTypeBuilder>> genTypeBuilders,
1087                                                      final BindingNamespaceType namespaceType) {
1088         checkArgument(basePackageName != null, "Base Package Name cannot be NULL.");
1089         checkArgument(refChoiceType != null, "Referenced Choice Type cannot be NULL.");
1090         checkArgument(choiceNode != null, "ChoiceNode cannot be NULL.");
1091
1092         for (final CaseSchemaNode caseNode : choiceNode.getCases().values()) {
1093             if (caseNode != null && resolveDataSchemaNodesCheck(module, schemaContext, caseNode)) {
1094                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(basePackageName, caseNode,
1095                         null, module, genCtx, schemaContext, verboseClassComments,
1096                         genTypeBuilders, typeProvider, namespaceType);
1097                 caseTypeBuilder.addImplementsType(refChoiceType);
1098                 caseTypeBuilder.setParentTypeForBuilder(refChoiceType.getParentTypeForBuilder());
1099                 annotateDeprecatedIfNecessary(caseNode.getStatus(), caseTypeBuilder);
1100                 genCtx.get(module).addCaseType(caseNode.getPath(), caseTypeBuilder);
1101                 if (BindingNamespaceType.isData(namespaceType)) {
1102                     genCtx.get(module).addChoiceToCaseMapping(refChoiceType, caseTypeBuilder, caseNode);
1103                 }
1104
1105                 resolveDataSchemaNodes(module, basePackageName, caseTypeBuilder,
1106                         (GeneratedTypeBuilder) refChoiceType.getParentTypeForBuilder(), caseNode.getChildNodes(),
1107                         genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
1108                 processUsesImplements(caseNode, module, schemaContext, genCtx, namespaceType);
1109             }
1110         }
1111     }
1112
1113     private static Type resolveAnyNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
1114             typeBuilder, final Map<Module, ModuleContext> genCtx, final DataSchemaNode node, final Module module,
1115                                                final TypeProvider typeProvider) {
1116
1117         final String anyName = node.getQName().getLocalName();
1118         if (anyName == null) {
1119             return null;
1120         }
1121
1122         Type returnType = Types.DOCUMENT;
1123         constructGetter(typeBuilder, anyName, node.getDescription().orElse(""), returnType, node.getStatus());
1124         return returnType;
1125     }
1126
1127     /**
1128      * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
1129      * or to <code>genTOBuilder</code> as property.
1130      *
1131      * @param nodeName             string contains the name of list
1132      * @param basePackageName      string contains the module package name
1133      * @param schemaNode           data schema node which should be added as getter method to
1134      *                             <code>typeBuilder</code> or as a property to
1135      *                             <code>genTOBuilder</code> if is part of the list key
1136      * @param typeBuilder          generated type builder for the list schema node
1137      * @param genTOBuilder         generated TO builder for the list keys
1138      * @param listKeys             list of string which contains QNames of the list keys
1139      * @param module               current module
1140      * @param typeProvider         provider that defines contract for generated types
1141      * @param schemaContext        schema context
1142      * @param genCtx               map of generated entities in context of YANG modules
1143      * @param genTypeBuilders      map of generated type builders
1144      * @param verboseClassComments generate verbose comments
1145      * @throws IllegalArgumentException <ul>
1146      *                                  <li>if <code>schemaNode</code> equals null</li>
1147      *                                  <li>if <code>typeBuilder</code> equals null</li>
1148      *                                  </ul>
1149      */
1150     private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
1151                                                     final DataSchemaNode schemaNode, final GeneratedTypeBuilder
1152                                                             typeBuilder,
1153                                                     final GeneratedTOBuilder genTOBuilder, final List<QName>
1154                                                             listKeys, final Module module,
1155                                                     final TypeProvider typeProvider, final SchemaContext
1156                                                             schemaContext, final Map<Module, ModuleContext> genCtx,
1157                                                     final Map<String, Map<String, GeneratedTypeBuilder>>
1158                                                             genTypeBuilders, final boolean verboseClassComments,
1159                                                     final BindingNamespaceType namespaceType) {
1160         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
1161         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
1162
1163         if (schemaNode instanceof LeafSchemaNode) {
1164             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1165             final QName leafQName = leaf.getQName();
1166
1167             final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module,
1168                     typeProvider, verboseClassComments);
1169             if (listKeys.contains(leafQName)) {
1170                 if (type == null) {
1171                     resolveLeafSchemaNodeAsProperty(nodeName, schemaContext, typeProvider, genCtx, genTOBuilder,
1172                             leaf, true,
1173                             module);
1174                 } else {
1175                     AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, genTOBuilder, leaf, type, true);
1176                 }
1177             }
1178         } else {
1179             if (schemaNode instanceof LeafListSchemaNode) {
1180                 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
1181                         typeProvider, genCtx, verboseClassComments);
1182             } else if (schemaNode instanceof ContainerSchemaNode) {
1183                 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
1184                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1185             } else if (schemaNode instanceof ListSchemaNode) {
1186                 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
1187                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1188             } else if (schemaNode instanceof ChoiceSchemaNode) {
1189                 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, typeBuilder,
1190                         (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType);
1191             }
1192         }
1193     }
1194
1195     private static void addSchemaNodeToListTypeBuilders(final String nodeName, final String basePackageName,
1196                                                         final DataSchemaNode schemaNode, final GeneratedTypeBuilder
1197                                                                 typeBuilder,
1198                                                         final GeneratedTypeBuilder genTypeBuilder, final List<QName>
1199                                                                 listKeys, final Module module,
1200                                                         final TypeProvider typeProvider, final SchemaContext
1201                                                                 schemaContext, final Map<Module, ModuleContext> genCtx,
1202                                                         final Map<String, Map<String, GeneratedTypeBuilder>>
1203                                                                 genTypeBuilders, final boolean verboseClassComments,
1204                                                         final BindingNamespaceType namespaceType) {
1205         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
1206         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
1207
1208         if (schemaNode instanceof LeafSchemaNode) {
1209             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1210             final QName leafQName = leaf.getQName();
1211             final Type type = resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, typeBuilder, genCtx, leaf, module,
1212                     typeProvider, verboseClassComments);
1213             if (listKeys.contains(leafQName)) {
1214                 resolveLeafSchemaNodeAsMethod(nodeName, schemaContext, genTypeBuilder, genCtx, leaf, module,
1215                         typeProvider, verboseClassComments);
1216             }
1217         } else {
1218             if (schemaNode instanceof LeafListSchemaNode) {
1219                 resolveLeafListSchemaNode(schemaContext, typeBuilder, (LeafListSchemaNode) schemaNode, module,
1220                         typeProvider, genCtx, verboseClassComments);
1221             } else if (schemaNode instanceof ContainerSchemaNode) {
1222                 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
1223                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1224             } else if (schemaNode instanceof ListSchemaNode) {
1225                 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
1226                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider, namespaceType);
1227             } else if (schemaNode instanceof ChoiceSchemaNode) {
1228                 choiceToGenType(module, schemaContext, verboseClassComments, basePackageName, typeBuilder, typeBuilder,
1229                         (ChoiceSchemaNode) schemaNode, genTypeBuilders, genCtx, typeProvider, namespaceType);
1230             }
1231         }
1232     }
1233
1234     private static boolean resolveLeafSchemaNodeAsProperty(final String nodeName, final SchemaContext schemaContext,
1235                                                            final TypeProvider
1236                                                                    typeProvider, final Map<Module, ModuleContext>
1237                                                                    genCtx, final GeneratedTOBuilder
1238                                                                    toBuilder, final LeafSchemaNode leaf, final
1239                                                            boolean isReadOnly, final Module module) {
1240
1241         if (leaf != null && toBuilder != null) {
1242             Type returnType;
1243             final TypeDefinition<?> typeDef = leaf.getType();
1244             if (typeDef instanceof UnionTypeDefinition) {
1245                 // GeneratedType for this type definition should be already
1246                 // created
1247                 final QName qname = typeDef.getQName();
1248                 final Module unionModule = schemaContext.findModule(qname.getModule()).get();
1249                 final ModuleContext mc = genCtx.get(unionModule);
1250                 returnType = mc.getTypedefs().get(typeDef.getPath());
1251             } else if (typeDef instanceof EnumTypeDefinition && typeDef.getBaseType() == null) {
1252                 // Annonymous enumeration (already generated, since it is inherited via uses).
1253                 LeafSchemaNode originalLeaf = (LeafSchemaNode) SchemaNodeUtils.getRootOriginalIfPossible(leaf);
1254                 QName qname = originalLeaf.getQName();
1255                 final Module enumModule = schemaContext.findModule(qname.getModule()).orElse(null);
1256                 returnType = genCtx.get(enumModule).getInnerType(originalLeaf.getType().getPath());
1257             } else {
1258                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, genCtx.get(module));
1259             }
1260             return AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(nodeName, toBuilder, leaf, returnType, isReadOnly);
1261         }
1262         return false;
1263     }
1264
1265     private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
1266         final TypeDefinition<?> baseType = typeDef.getBaseType();
1267         return baseType != null && baseType.getBaseType() != null ? baseType : typeDef;
1268     }
1269
1270     @SuppressWarnings({"rawtypes", "unchecked"})
1271     private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
1272                                                               final GeneratedTypeBuilder childOf, final
1273                                                               DataSchemaNode node, final SchemaContext
1274                                                                       schemaContext,
1275                                                               final boolean verboseClassComments, final Map<Module,
1276             ModuleContext> genCtx, final Map<String, Map<String,
1277             GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider, final BindingNamespaceType
1278                                                                       namespaceType) {
1279
1280         final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, node, childOf, module,
1281                 genCtx, schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
1282         annotateDeprecatedIfNecessary(node.getStatus(), genType);
1283         genType.setModuleName(module.getName());
1284         if (verboseClassComments) {
1285             YangSourceDefinition.of(module, node).ifPresent(genType::setYangSourceDefinition);
1286             TypeComments.description(node).ifPresent(genType::addComment);
1287             node.getDescription().ifPresent(genType::setDescription);
1288             node.getReference().ifPresent(genType::setReference);
1289         }
1290         genType.setSchemaPath((List) node.getPath().getPathFromRoot());
1291         if (BindingNamespaceType.isData(namespaceType)) {
1292             genType.setParentTypeForBuilder(childOf);
1293         }
1294
1295         if (node instanceof DataNodeContainer) {
1296             genCtx.get(module).addChildNodeType(node, genType);
1297         }
1298         return genType;
1299     }
1300
1301     /**
1302      * Converts all <b>groupings</b> of the module to the list of
1303      * <code>Type</code> objects. Firstly are groupings sorted according mutual
1304      * dependencies. At least dependent (independent) groupings are in the list
1305      * saved at first positions. For every grouping the record is added to map
1306      * {@link ModuleContext#groupings allGroupings}
1307      *
1308      * @param module               current module
1309      * @param groupings            collection of groupings from which types will be generated
1310      * @param typeProvider         provider that defines contract for generated types
1311      * @param schemaContext        schema context
1312      * @param genCtx               map of generated entities in context of YANG modules
1313      * @param genTypeBuilders      map of generated type builders
1314      * @param verboseClassComments generate verbose comments
1315      */
1316     static Map<Module, ModuleContext> groupingsToGenTypes(final Module module, final Collection<GroupingDefinition>
1317             groupings, Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean
1318                                                                   verboseClassComments, final Map<String, Map<String,
1319             GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
1320         final String basePackageName = BindingMapping.getRootPackageName(module);
1321         final List<GroupingDefinition> groupingsSortedByDependencies = new GroupingDefinitionDependencySort()
1322                 .sort(groupings);
1323         for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
1324             genCtx = groupingToGenType(basePackageName, grouping, module, genCtx, schemaContext,
1325                     verboseClassComments, genTypeBuilders, typeProvider);
1326         }
1327         return genCtx;
1328     }
1329
1330     /**
1331      * Converts individual grouping to GeneratedType. Firstly generated type
1332      * builder is created and every child node of grouping is resolved to the
1333      * method.
1334      *
1335      * @param basePackageName      string contains the module package name
1336      * @param grouping             GroupingDefinition which contains data about grouping
1337      * @param module               current module
1338      * @param typeProvider         provider that defines contract for generated types
1339      * @param schemaContext        schema context
1340      * @param genCtx               map of generated entities in context of YANG modules
1341      * @param genTypeBuilders      map of generated type builders
1342      * @param verboseClassComments generate verbose comments
1343      * @return GeneratedType which is generated from grouping (object of type
1344      *      <code>GroupingDefinition</code>)
1345      */
1346     private static Map<Module, ModuleContext> groupingToGenType(final String basePackageName,
1347             final GroupingDefinition grouping, final Module module, Map<Module, ModuleContext> genCtx,
1348             final SchemaContext schemaContext, final boolean verboseClassComments,
1349             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
1350         final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(basePackageName, grouping, null, module,
1351                 genCtx,
1352                 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping);
1353         annotateDeprecatedIfNecessary(grouping.getStatus(), genType);
1354         genCtx.get(module).addGroupingType(grouping, genType);
1355         resolveDataSchemaNodes(module, basePackageName, genType, genType, grouping.getChildNodes(), genCtx,
1356                 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, BindingNamespaceType.Grouping);
1357         genCtx = processUsesImplements(grouping, module, schemaContext, genCtx, BindingNamespaceType.Grouping);
1358         return genCtx;
1359     }
1360
1361     /**
1362      * //TODO: add information about multiple base identities in YANG 1.1
1363      * Converts the <b>identity</b> object to GeneratedType. Firstly it is
1364      * created transport object builder. If identity contains base identity then
1365      * reference to base identity is added to superior identity as its extend.
1366      * If identity doesn't contain base identity then only reference to abstract
1367      * class {@link org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode
1368      * BaseIdentity} is added
1369      *
1370      * @param module          current module
1371      * @param basePackageName string contains the module package name
1372      * @param identity        IdentitySchemaNode which contains data about identity
1373      * @param schemaContext   SchemaContext which is used to get package and name
1374      *                        information about base of identity
1375      * @param genCtx          generated context
1376      * @return returns generated context
1377      */
1378     static Map<Module, ModuleContext> identityToGenType(final Module module, final String basePackageName,
1379                                                         final IdentitySchemaNode identity, final SchemaContext
1380                                                                 schemaContext, final Map<Module, ModuleContext> genCtx,
1381                                                         final boolean verboseClassComments) {
1382
1383         resolveIdentitySchemaNode(basePackageName, schemaContext, identity, module, verboseClassComments, genCtx);
1384         return genCtx;
1385     }
1386
1387     private static GeneratedTypeBuilder resolveIdentitySchemaNode(final String basePackageName, final SchemaContext
1388             schemaContext,
1389                                                                   final IdentitySchemaNode identity, final Module
1390                                                                           module, final boolean verboseClassComments,
1391                                                                   final Map<Module, ModuleContext> genCtx) {
1392         requireNonNull(identity, "Identity can not be null!");
1393
1394         //check first if identity has been resolved as base identity of some other one
1395         GeneratedTypeBuilder newType = findIdentityByQname(identity.getQName(), genCtx);
1396         if (newType == null) {
1397             final Module parentModule = SchemaContextUtil.findParentModule(schemaContext, identity);
1398             Preconditions.checkState(module.equals(parentModule),
1399                     "If the type is null ,it must be in the same module, otherwise it must has been"
1400                             + "resolved by an imported module.");
1401
1402             final String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, identity
1403                             .getPath(),
1404                     BindingNamespaceType.Identity);
1405             newType = new GeneratedTypeBuilderImpl(packageName, identity.getQName().getLocalName(), true, false,
1406                     genCtx.get(module));
1407
1408             final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
1409             if (baseIdentities.size() == 0) {
1410                 //no base - abstract
1411                 final GeneratedTypeBuilderImpl genType = new GeneratedTypeBuilderImpl(BaseIdentity.class.getPackage()
1412                         .getName(),
1413                         BaseIdentity.class.getSimpleName(), genCtx.get(module));
1414                 newType.addImplementsType(genType.toInstance());
1415             } else {
1416                 //multiple bases - inheritance
1417                 for (IdentitySchemaNode baseIdentity : baseIdentities) {
1418                     GeneratedTypeBuilder baseType = resolveIdentitySchemaNode(basePackageName, schemaContext,
1419                             baseIdentity, module, verboseClassComments, genCtx);
1420                     newType.addImplementsType(baseType.toInstance());
1421                 }
1422             }
1423
1424             if (verboseClassComments) {
1425                 YangSourceDefinition.of(module).ifPresent(newType::setYangSourceDefinition);
1426                 TypeComments.description(module).ifPresent(newType::addComment);
1427                 module.getDescription().ifPresent(newType::setDescription);
1428                 module.getReference().ifPresent(newType::setReference);
1429             }
1430             newType.setSchemaPath((List) identity.getPath().getPathFromRoot());
1431
1432             qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
1433
1434             genCtx.get(module).addIdentityType(identity.getQName(), newType);
1435         }
1436         return newType;
1437     }
1438 }