Bug 1411 #3 BindingGeneratorImpl decomposition - Leafs
[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 org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder;
12 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.augGenTypeName;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription;
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.util.BindingGeneratorUtil.packageNameForGeneratedType;
22 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
23
24 import com.google.common.annotations.Beta;
25 import com.google.common.base.Preconditions;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
30 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
31 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
32 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
33 import org.opendaylight.mdsal.binding.javav2.generator.util.NonJavaCharsConverter;
34 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
35 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
36 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
37 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
38 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
39 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
40 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
41 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
42 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
43 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
44 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
45 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
46 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
47 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
50 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
52 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
54 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.Module;
56 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
57 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
58 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
59 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
60 import org.opendaylight.yangtools.yang.model.api.UsesNode;
61 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
62 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
63 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
64 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
65
66 /**
67  * Helper util class used for generation of types in Binding spec v2.
68  */
69 @Beta
70 final class GenHelperUtil {
71
72     private GenHelperUtil() {
73         throw new UnsupportedOperationException("Util class");
74     }
75
76     /**
77      * Create GeneratedTypeBuilder object from module argument.
78      *
79      * @param module
80      *            Module object from which builder will be created
81      * @param genCtx
82      * @param verboseClassComments
83      *
84      * @return <code>GeneratedTypeBuilder</code> which is internal
85      *         representation of the module
86      * @throws IllegalArgumentException
87      *             if module is null
88      */
89     static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
90         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
91
92         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
93         addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
94         moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
95         moduleDataTypeBuilder.addComment(module.getDescription());
96         moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
97         moduleDataTypeBuilder.setReference(module.getReference());
98         return moduleDataTypeBuilder;
99     }
100
101     /**
102      * Generates type builder for <code>module</code>.
103      *
104      * @param module
105      *            Module which is source of package name for generated type
106      *            builder
107      * @param postfix
108      *            string which is added to the module class name representation
109      *            as suffix
110      * @param verboseClassComments
111      * @return instance of GeneratedTypeBuilder which represents
112      *         <code>module</code>.
113      * @throws IllegalArgumentException
114      *             if <code>module</code> is null
115      */
116     private static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
117             verboseClassComments) {
118         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
119         final String packageName = BindingMapping.getRootPackageName(module);
120         final String moduleName = BindingMapping.getClassName(NonJavaCharsConverter.convertIdentifier(module.getName
121                 (), JavaIdentifier.CLASS)) + postfix;
122
123         final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
124         moduleBuilder.setDescription(createDescription(module, verboseClassComments));
125         moduleBuilder.setReference(module.getReference());
126         moduleBuilder.setModuleName(moduleName);
127
128         return moduleBuilder;
129     }
130
131     /**
132      * Adds the implemented types to type builder.
133      *
134      * The method passes through the list of <i>uses</i> in
135      * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
136      * generated type from all groupings
137      * allGroupings} which is added as <i>implements type</i> to
138      * <code>builder</code>
139      *
140      * @param dataNodeContainer
141      *            element which contains the list of used YANG groupings
142      * @param builder
143      *            builder to which are added implemented types according to
144      *            <code>dataNodeContainer</code>
145      * @param genCtx generated context
146      * @return generated type builder with all implemented types
147      */
148     private static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
149                           final GeneratedTypeBuilder builder, final Map<Module, ModuleContext> genCtx) {
150         for (final UsesNode usesNode : dataNodeContainer.getUses()) {
151             final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
152             if (genType == null) {
153                 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
154                     + builder.getName());
155             }
156             builder.addImplementsType(genType);
157         }
158         return builder;
159     }
160
161      static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
162         for (final ModuleContext ctx : genCtx.values()) {
163             final GeneratedTypeBuilder result = ctx.getGrouping(path);
164             if (result != null) {
165                 return result;
166             }
167         }
168         return null;
169      }
170
171     /**
172      * Adds the methods to <code>typeBuilder</code> which represent subnodes of
173      * node for which <code>typeBuilder</code> was created.
174      *
175      * The subnodes aren't mapped to the methods if they are part of grouping or
176      * augment (in this case are already part of them).
177      *
178      * @param module
179      *            current module
180      * @param basePackageName
181      *            string contains the module package name
182      * @param parent
183      *            generated type builder which represents any node. The subnodes
184      *            of this node are added to the <code>typeBuilder</code> as
185      *            methods. The subnode can be of type leaf, leaf-list, list,
186      *            container, choice.
187      * @param childOf
188      *            parent type
189      * @param schemaNodes
190      *            set of data schema nodes which are the children of the node
191      *            for which <code>typeBuilder</code> was created
192      * @return generated type builder which is the same builder as input
193      *         parameter. The getter methods (representing child nodes) could be
194      *         added to it.
195      */
196     static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
197                           final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
198                           final Iterable<DataSchemaNode> schemaNodes, final Map<Module, ModuleContext> genCtx,
199                           final SchemaContext schemaContext, final boolean verboseClassComments,
200                           final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
201                           final TypeProvider typeProvider) {
202
203         if (schemaNodes != null && parent != null) {
204             for (final DataSchemaNode schemaNode : schemaNodes) {
205                 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
206                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
207                             schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
208                 }
209             }
210         }
211         return parent;
212     }
213
214     static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
215             schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
216                                                               final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
217         return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
218                 verboseClassComments, genTypeBuilders);
219     }
220
221     static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
222                         DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx,
223                         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
224                         final boolean verboseClassComments, final TypeProvider typeProvider) {
225         final String basePackageName = BindingMapping.getRootPackageName(module);
226         for (final UsesNode usesNode : node.getUses()) {
227             for (final AugmentationSchema augment : usesNode.getAugmentations()) {
228                 genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
229                         usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider);
230                 genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders,
231                         verboseClassComments, typeProvider);
232             }
233         }
234         return genCtx;
235     }
236
237     static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
238         for (final ModuleContext ctx : genCtx.values()) {
239             final GeneratedTypeBuilder result = ctx.getChildNode(path);
240             if (result != null) {
241                 return result;
242             }
243         }
244         return null;
245     }
246
247     static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
248         for (final ModuleContext ctx : genCtx.values()) {
249             final GeneratedTypeBuilder result = ctx.getCase(path);
250             if (result != null) {
251                 return result;
252             }
253         }
254         return null;
255     }
256
257     /**
258      * Returns a generated type builder for an augmentation.
259      *
260      * The name of the type builder is equal to the name of augmented node with
261      * serial number as suffix.
262      *
263      * @param module
264      *            current module
265      * @param augmentPackageName
266      *            string with contains the package name to which the augment
267      *            belongs
268      * @param basePackageName
269      *            string with the package name to which the augmented node
270      *            belongs
271      * @param targetTypeRef
272      *            target type
273      * @param augSchema
274      *            augmentation schema which contains data about the child nodes
275      *            and uses of augment
276      * @return generated type builder for augment in genCtx
277      */
278     static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
279                 final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
280                 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx) {
281
282         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
283         if (augmentBuilders == null) {
284             augmentBuilders = new HashMap<>();
285             genTypeBuilders.put(augmentPackageName, augmentBuilders);
286         }
287         final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
288
289         String augTypeName;
290         if (augIdentifier != null) {
291             augTypeName = BindingMapping.getClassName(augIdentifier);
292         } else {
293             augTypeName = augGenTypeName(augmentBuilders, targetTypeRef.getName());
294         }
295
296         GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
297
298         augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
299         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
300         annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
301         augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
302
303         augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
304                 .getChildNodes());
305         augmentBuilders.put(augTypeName, augTypeBuilder);
306
307         if(!augSchema.getChildNodes().isEmpty()) {
308             genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
309
310         }
311         genCtx.get(module).addAugmentType(augTypeBuilder);
312         return genCtx;
313     }
314
315     /**
316      * Adds the methods to <code>typeBuilder</code> what represents subnodes of
317      * node for which <code>typeBuilder</code> was created.
318      *
319      * @param module
320      *            current module
321      * @param basePackageName
322      *            string contains the module package name
323      * @param typeBuilder
324      *            generated type builder which represents any node. The subnodes
325      *            of this node are added to the <code>typeBuilder</code> as
326      *            methods. The subnode can be of type leaf, leaf-list, list,
327      *            container, choice.
328      * @param childOf
329      *            parent type
330      * @param schemaNodes
331      *            set of data schema nodes which are the children of the node
332      *            for which <code>typeBuilder</code> was created
333      * @return generated type builder which is the same object as the input
334      *         parameter <code>typeBuilder</code>. The getter method could be
335      *         added to it.
336      */
337     private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
338                                                         final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
339                                                         final Iterable<DataSchemaNode> schemaNodes) {
340         if (schemaNodes != null && typeBuilder != null) {
341             for (final DataSchemaNode schemaNode : schemaNodes) {
342                 if (!schemaNode.isAugmenting()) {
343                     //TODO: design decomposition and implement it
344                     //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
345                 }
346             }
347         }
348         return typeBuilder;
349     }
350
351     /**
352      * Instantiates generated type builder with <code>packageName</code> and
353      * <code>schemaNode</code>.
354      *
355      * The new builder always implements
356      * {@link TreeNode TreeNode}.<br>
357      * If <code>schemaNode</code> is instance of GroupingDefinition it also
358      * implements {@link Augmentable
359      * Augmentable}.<br>
360      * If <code>schemaNode</code> is instance of
361      * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
362      * DataNodeContainer} it can also implement nodes which are specified in
363      * <i>uses</i>.
364      *
365      * @param packageName
366      *            string with the name of the package to which
367      *            <code>schemaNode</code> belongs.
368      * @param schemaNode
369      *            schema node for which is created generated type builder
370      * @param parent
371      *            parent type (can be null)
372      * @param schemaContext schema context
373      * @return generated type builder <code>schemaNode</code>
374      */
375     private static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
376             schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
377             final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
378
379         GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
380                 verboseClassComments, genTypeBuilders);
381         if (parent == null) {
382             it.addImplementsType(BindingTypes.TREE_NODE);
383         } else {
384             it.addImplementsType(BindingTypes.treeChildNode(parent));
385         }
386         if (!(schemaNode instanceof GroupingDefinition)) {
387             it.addImplementsType(BindingTypes.augmentable(it));
388         }
389
390         if (schemaNode instanceof DataNodeContainer) {
391             //TODO: design decomposition and implement it
392             //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
393             it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
394         }
395
396         return it;
397     }
398
399     /**
400      * Returns reference to generated type builder for specified
401      * <code>schemaNode</code> with <code>packageName</code>.
402      *
403      * Firstly the generated type builder is searched in
404      * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
405      * found it is created and added to <code>genTypeBuilders</code>.
406      *
407      * @param packageName
408      *            string with the package name to which returning generated type
409      *            builder belongs
410      * @param schemaNode
411      *            schema node which provide data about the schema node name
412      * @param schemaContext
413      * @param prefix
414      *            return type name prefix
415      * @return generated type builder for <code>schemaNode</code>
416      * @throws IllegalArgumentException
417      *             <ul>
418      *             <li>if <code>schemaNode</code> is null</li>
419      *             <li>if <code>packageName</code> is null</li>
420      *             <li>if QName of schema node is null</li>
421      *             <li>if schemaNode name is null</li>
422      *             </ul>
423      *
424      */
425     private static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
426                        final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
427                        final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
428
429         Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
430         Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
431         final String schemaNodeName = schemaNode.getQName().getLocalName();
432         Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
433
434         String genTypeName;
435         if (prefix == null) {
436             genTypeName = BindingMapping
437                     .getClassName(NonJavaCharsConverter.normalizeClassIdentifier(packageName, schemaNodeName));
438         } else {
439             genTypeName = prefix + BindingMapping
440                     .getClassName(NonJavaCharsConverter.normalizeClassIdentifier(packageName, schemaNodeName));
441         }
442
443         final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
444         final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
445         qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
446         newType.addComment(schemaNode.getDescription());
447         newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
448         newType.setReference(schemaNode.getReference());
449         newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
450         newType.setModuleName(module.getName());
451
452         if (!genTypeBuilders.containsKey(packageName)) {
453             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
454             builders.put(genTypeName, newType);
455             genTypeBuilders.put(packageName, builders);
456         } else {
457             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
458             if (!builders.containsKey(genTypeName)) {
459                 builders.put(genTypeName, newType);
460             }
461         }
462         return newType;
463
464     }
465
466     private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
467         final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module,
468         final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
469         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
470         //TODO: implement rest of schema nodes GTO building
471         if (node != null && typeBuilder != null) {
472             if (node instanceof ContainerSchemaNode) {
473                 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
474                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
475             } else if (node instanceof LeafSchemaNode) {
476                 resolveLeafSchemaNodeAsMethod(schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
477                         typeProvider);
478             }
479         }
480
481     }
482
483     private static void containerToGenType(final Module module, final String basePackageName,
484         final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node,
485         final SchemaContext schemaContext, final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
486         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
487
488         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
489                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
490         if (genType != null) {
491             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType, node.getStatus());
492             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
493                     schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
494         }
495     }
496
497     /**
498      * Converts <code>leaf</code> to the getter method which is added to
499      * <code>typeBuilder</code>.
500      *
501      * @param typeBuilder
502      *            generated type builder to which is added getter method as
503      *            <code>leaf</code> mapping
504      * @param leaf
505      *            leaf schema node which is mapped as getter method which is
506      *            added to <code>typeBuilder</code>
507      * @param module
508      *            Module in which type was defined
509      * @return boolean value
510      *         <ul>
511      *         <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
512      *         null</li>
513      *         <li>true - in other cases</li>
514      *         </ul>
515      */
516     private static Type resolveLeafSchemaNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
517             typeBuilder, final Map<Module, ModuleContext> genCtx, final LeafSchemaNode leaf, final Module module,
518             final TypeProvider typeProvider) {
519         if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
520             return null;
521         }
522
523         final String leafName = leaf.getQName().getLocalName();
524         if (leafName == null) {
525             return null;
526         }
527
528         final Module parentModule = findParentModule(schemaContext, leaf);
529         Type returnType = null;
530
531         final TypeDefinition<?> typeDef = leaf.getType();
532         if (isInnerType(leaf, typeDef)) {
533             if (typeDef instanceof EnumTypeDefinition) {
534                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
535                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
536                 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
537                         genCtx, typeBuilder, module);
538                 if (enumBuilder != null) {
539                     returnType = enumBuilder.toInstance(typeBuilder);
540                 }
541                 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
542             } else if (typeDef instanceof UnionTypeDefinition) {
543                 GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
544                         typeProvider, schemaContext);
545                 if (genTOBuilder != null) {
546                     //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
547                     returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider);
548                 }
549             } else if (typeDef instanceof BitsTypeDefinition) {
550                 GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
551                         typeProvider, schemaContext);
552                 if (genTOBuilder != null) {
553                     returnType = genTOBuilder.toInstance();
554                 }
555             } else {
556                 // It is constrained version of already declared type (inner declared type exists,
557                 // onlyfor special cases (Enum, Union, Bits), which were already checked.
558                 // In order to get proper class we need to look up closest derived type
559                 // and apply restrictions from leaf type
560                 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
561                 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
562                         restrictions);
563             }
564         } else {
565             final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
566             returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
567         }
568
569         if (returnType == null) {
570             return null;
571         }
572
573         if (typeDef instanceof EnumTypeDefinition) {
574             ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
575         }
576
577         String leafDesc = leaf.getDescription();
578         if (leafDesc == null) {
579             leafDesc = "";
580         }
581
582         final MethodSignatureBuilder getter = constructGetter(typeBuilder, leafName, leafDesc, returnType, leaf.getStatus());
583
584         //FIXME: deal with context-ref
585         return returnType;
586     }
587
588     private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
589         final TypeDefinition<?> baseType = typeDef.getBaseType();
590         return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef;
591     }
592
593     private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
594         final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
595         final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
596         GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
597
598         if (node.isAugmenting() || node.isAddedByUses()) {
599             return null;
600         }
601         final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
602         final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
603                 genCtx, schemaContext, verboseClassComments, genTypeBuilders);
604         genType.addComment(node.getDescription());
605         annotateDeprecatedIfNecessary(node.getStatus(), genType);
606         genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
607         genType.setModuleName(module.getName());
608         genType.setReference(node.getReference());
609         genType.setSchemaPath((List) node.getPath().getPathFromRoot());
610         if (node instanceof DataNodeContainer) {
611             genCtx.get(module).addChildNodeType(node, genType);
612             //TODO: implement groupings to GTO building first
613             // groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
614             processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
615                     verboseClassComments, typeProvider);
616         }
617         return genType;
618     }
619
620 }