Code generator prototype - Binding specification v2
[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 org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.addTOToTypeBuilder;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.augGenTypeName;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.constructGetter;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createDescription;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.createReturnTypeForUnion;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.getAugmentIdentifier;
19 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.isInnerType;
20 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.qNameConstant;
21 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveInnerEnumFromTypeDefinition;
22 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.resolveListKeyTOBuilder;
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.NOTIFICATION;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
28 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
29
30 import com.google.common.annotations.Beta;
31 import com.google.common.base.Preconditions;
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
36 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
37 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
38 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
39 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
40 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
41 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
43 import org.opendaylight.mdsal.binding.javav2.generator.yang.types.TypeProviderImpl;
44 import org.opendaylight.mdsal.binding.javav2.model.api.AccessModifier;
45 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
46 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
47 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
48 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
49 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.EnumBuilder;
50 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedPropertyBuilder;
51 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
52 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
53 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
54 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
55 import org.opendaylight.mdsal.binding.javav2.spec.structural.Augmentable;
56 import org.opendaylight.mdsal.binding.javav2.util.BindingMapping;
57 import org.opendaylight.yangtools.yang.common.QName;
58 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
59 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
61 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
62 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
63 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
65 import org.opendaylight.yangtools.yang.model.api.Module;
66 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
67 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
68 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
69 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
70 import org.opendaylight.yangtools.yang.model.api.Status;
71 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
72 import org.opendaylight.yangtools.yang.model.api.UsesNode;
73 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
74 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
75 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
76 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
77
78 /**
79  * Helper util class used for generation of types in Binding spec v2.
80  */
81 @Beta
82 final class GenHelperUtil {
83
84     private GenHelperUtil() {
85         throw new UnsupportedOperationException("Util class");
86     }
87
88     /**
89      * Create GeneratedTypeBuilder object from module argument.
90      *
91      * @param module
92      *            Module object from which builder will be created
93      * @param genCtx
94      * @param verboseClassComments
95      *
96      * @return <code>GeneratedTypeBuilder</code> which is internal
97      *         representation of the module
98      * @throws IllegalArgumentException
99      *             if module is null
100      */
101     static GeneratedTypeBuilder moduleToDataType(final Module module, final Map<Module, ModuleContext> genCtx, final boolean verboseClassComments) {
102         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
103
104         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data", verboseClassComments);
105         addImplementedInterfaceFromUses(module, moduleDataTypeBuilder, genCtx);
106         moduleDataTypeBuilder.addImplementsType(BindingTypes.TREE_ROOT);
107         moduleDataTypeBuilder.addComment(module.getDescription());
108         moduleDataTypeBuilder.setDescription(createDescription(module, verboseClassComments));
109         moduleDataTypeBuilder.setReference(module.getReference());
110         return moduleDataTypeBuilder;
111     }
112
113     /**
114      * Generates type builder for <code>module</code>.
115      *
116      * @param module
117      *            Module which is source of package name for generated type
118      *            builder
119      * @param postfix
120      *            string which is added to the module class name representation
121      *            as suffix
122      * @param verboseClassComments
123      * @return instance of GeneratedTypeBuilder which represents
124      *         <code>module</code>.
125      * @throws IllegalArgumentException
126      *             if <code>module</code> is null
127      */
128     static GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix, final boolean
129             verboseClassComments) {
130         Preconditions.checkArgument(module != null, "Module reference cannot be NULL.");
131         final String packageName = BindingMapping.getRootPackageName(module);
132         // underscore used as separator for distinction of module name parts
133         final String moduleName = new StringBuilder(module.getName()).append('_').append(postfix).toString();
134
135         final GeneratedTypeBuilderImpl moduleBuilder = new GeneratedTypeBuilderImpl(packageName, moduleName);
136         moduleBuilder.setDescription(createDescription(module, verboseClassComments));
137         moduleBuilder.setReference(module.getReference());
138         moduleBuilder.setModuleName(moduleName);
139
140         return moduleBuilder;
141     }
142
143     /**
144      * Adds the implemented types to type builder.
145      *
146      * The method passes through the list of <i>uses</i> in
147      * {@code dataNodeContainer}. For every <i>use</i> is obtained corresponding
148      * generated type from all groupings
149      * allGroupings} which is added as <i>implements type</i> to
150      * <code>builder</code>
151      *
152      * @param dataNodeContainer
153      *            element which contains the list of used YANG groupings
154      * @param builder
155      *            builder to which are added implemented types according to
156      *            <code>dataNodeContainer</code>
157      * @param genCtx generated context
158      * @return generated type builder with all implemented types
159      */
160     static GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
161                           final GeneratedTypeBuilder builder, final Map<Module, ModuleContext> genCtx) {
162         for (final UsesNode usesNode : dataNodeContainer.getUses()) {
163             final GeneratedType genType = findGroupingByPath(usesNode.getGroupingPath(), genCtx).toInstance();
164             if (genType == null) {
165                 throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
166                     + builder.getName());
167             }
168             builder.addImplementsType(genType);
169         }
170         return builder;
171     }
172
173      static GeneratedTypeBuilder findGroupingByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
174         for (final ModuleContext ctx : genCtx.values()) {
175             final GeneratedTypeBuilder result = ctx.getGrouping(path);
176             if (result != null) {
177                 return result;
178             }
179         }
180         return null;
181      }
182
183     /**
184      * Adds the methods to <code>typeBuilder</code> which represent subnodes of
185      * node for which <code>typeBuilder</code> was created.
186      *
187      * The subnodes aren't mapped to the methods if they are part of grouping or
188      * augment (in this case are already part of them).
189      *
190      * @param module
191      *            current module
192      * @param basePackageName
193      *            string contains the module package name
194      * @param parent
195      *            generated type builder which represents any node. The subnodes
196      *            of this node are added to the <code>typeBuilder</code> as
197      *            methods. The subnode can be of type leaf, leaf-list, list,
198      *            container, choice.
199      * @param childOf
200      *            parent type
201      * @param schemaNodes
202      *            set of data schema nodes which are the children of the node
203      *            for which <code>typeBuilder</code> was created
204      * @return generated type builder which is the same builder as input
205      *         parameter. The getter methods (representing child nodes) could be
206      *         added to it.
207      */
208     static GeneratedTypeBuilder resolveDataSchemaNodes(final Module module, final String basePackageName,
209                           final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf,
210                           final Iterable<DataSchemaNode> schemaNodes, final Map<Module, ModuleContext> genCtx,
211                           final SchemaContext schemaContext, final boolean verboseClassComments,
212                           final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
213                           final TypeProvider typeProvider) {
214
215         if (schemaNodes != null && parent != null) {
216             for (final DataSchemaNode schemaNode : schemaNodes) {
217                 if (!schemaNode.isAugmenting() && !schemaNode.isAddedByUses()) {
218                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, parent, childOf, module, genCtx,
219                             schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
220                 }
221             }
222         }
223         return parent;
224     }
225
226     static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
227             schemaNode, final Module module, final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext,
228                                                               final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
229         return addDefaultInterfaceDefinition(packageName, schemaNode, null, module, genCtx, schemaContext,
230                 verboseClassComments, genTypeBuilders);
231     }
232
233     static Map<Module, ModuleContext> processUsesAugments(final SchemaContext schemaContext, final
234                         DataNodeContainer node, final Module module, Map<Module, ModuleContext> genCtx,
235                         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders,
236                         final boolean verboseClassComments, final TypeProvider typeProvider) {
237         final String basePackageName = BindingMapping.getRootPackageName(module);
238         for (final UsesNode usesNode : node.getUses()) {
239             for (final AugmentationSchema augment : usesNode.getAugmentations()) {
240                 genCtx = AugmentToGenType.usesAugmentationToGenTypes(schemaContext, basePackageName, augment, module,
241                         usesNode, node, genCtx, genTypeBuilders, verboseClassComments, typeProvider);
242                 genCtx = processUsesAugments(schemaContext, augment, module, genCtx, genTypeBuilders,
243                         verboseClassComments, typeProvider);
244             }
245         }
246         return genCtx;
247     }
248
249     static GeneratedTypeBuilder findChildNodeByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
250         for (final ModuleContext ctx : genCtx.values()) {
251             final GeneratedTypeBuilder result = ctx.getChildNode(path);
252             if (result != null) {
253                 return result;
254             }
255         }
256         return null;
257     }
258
259     static GeneratedTypeBuilder findCaseByPath(final SchemaPath path, final Map<Module, ModuleContext> genCtx) {
260         for (final ModuleContext ctx : genCtx.values()) {
261             final GeneratedTypeBuilder result = ctx.getCase(path);
262             if (result != null) {
263                 return result;
264             }
265         }
266         return null;
267     }
268
269     /**
270      * Returns a generated type builder for an augmentation.
271      *
272      * The name of the type builder is equal to the name of augmented node with
273      * serial number as suffix.
274      *
275      * @param module
276      *            current module
277      * @param augmentPackageName
278      *            string with contains the package name to which the augment
279      *            belongs
280      * @param basePackageName
281      *            string with the package name to which the augmented node
282      *            belongs
283      * @param targetTypeRef
284      *            target type
285      * @param augSchema
286      *            augmentation schema which contains data about the child nodes
287      *            and uses of augment
288      * @return generated type builder for augment in genCtx
289      */
290     static Map<Module, ModuleContext> addRawAugmentGenTypeDefinition(final Module module, final String augmentPackageName,
291                 final String basePackageName, final Type targetTypeRef, final AugmentationSchema augSchema,
292                 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx) {
293
294         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
295         if (augmentBuilders == null) {
296             augmentBuilders = new HashMap<>();
297             genTypeBuilders.put(augmentPackageName, augmentBuilders);
298         }
299         String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
300
301         if (augIdentifier == null) {
302             augIdentifier = augGenTypeName(augmentBuilders, targetTypeRef.getName());
303         }
304
305         GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augIdentifier);
306
307         augTypeBuilder.addImplementsType(BindingTypes.TREE_NODE);
308         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
309         annotateDeprecatedIfNecessary(augSchema.getStatus(), augTypeBuilder);
310         augTypeBuilder = addImplementedInterfaceFromUses(augSchema, augTypeBuilder, genCtx);
311
312         augTypeBuilder = augSchemaNodeToMethods(module, basePackageName, augTypeBuilder, augTypeBuilder, augSchema
313                 .getChildNodes());
314         augmentBuilders.put(augTypeBuilder.getName(), augTypeBuilder);
315
316         if(!augSchema.getChildNodes().isEmpty()) {
317             genCtx.get(module).addTypeToAugmentation(augTypeBuilder, augSchema);
318
319         }
320         genCtx.get(module).addAugmentType(augTypeBuilder);
321         return genCtx;
322     }
323
324     /**
325      * Adds the methods to <code>typeBuilder</code> what represents subnodes of
326      * node for which <code>typeBuilder</code> was created.
327      *
328      * @param module
329      *            current module
330      * @param basePackageName
331      *            string contains the module package name
332      * @param typeBuilder
333      *            generated type builder which represents any node. The subnodes
334      *            of this node are added to the <code>typeBuilder</code> as
335      *            methods. The subnode can be of type leaf, leaf-list, list,
336      *            container, choice.
337      * @param childOf
338      *            parent type
339      * @param schemaNodes
340      *            set of data schema nodes which are the children of the node
341      *            for which <code>typeBuilder</code> was created
342      * @return generated type builder which is the same object as the input
343      *         parameter <code>typeBuilder</code>. The getter method could be
344      *         added to it.
345      */
346     private static GeneratedTypeBuilder augSchemaNodeToMethods(final Module module, final String basePackageName,
347             final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf,
348             final Iterable<DataSchemaNode> schemaNodes) {
349         if (schemaNodes != null && typeBuilder != null) {
350             for (final DataSchemaNode schemaNode : schemaNodes) {
351                 if (!schemaNode.isAugmenting()) {
352                     //TODO: design decomposition and implement it
353                     //addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder, childOf, module);
354                 }
355             }
356         }
357         return typeBuilder;
358     }
359
360     /**
361      * Instantiates generated type builder with <code>packageName</code> and
362      * <code>schemaNode</code>.
363      *
364      * The new builder always implements
365      * {@link TreeNode TreeNode}.<br>
366      * If <code>schemaNode</code> is instance of GroupingDefinition it also
367      * implements {@link Augmentable
368      * Augmentable}.<br>
369      * If <code>schemaNode</code> is instance of
370      * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
371      * DataNodeContainer} it can also implement nodes which are specified in
372      * <i>uses</i>.
373      *
374      * @param packageName
375      *            string with the name of the package to which
376      *            <code>schemaNode</code> belongs.
377      * @param schemaNode
378      *            schema node for which is created generated type builder
379      * @param parent
380      *            parent type (can be null)
381      * @param schemaContext schema context
382      * @return generated type builder <code>schemaNode</code>
383      */
384     static GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode
385             schemaNode, final Type parent, final Module module, final Map<Module, ModuleContext> genCtx,
386             final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
387
388         GeneratedTypeBuilder it = addRawInterfaceDefinition(packageName, schemaNode, schemaContext, "",
389                 verboseClassComments, genTypeBuilders);
390         if (parent == null) {
391             it.addImplementsType(BindingTypes.TREE_NODE);
392         } else {
393             if (parent instanceof ListSchemaNode) {
394                 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
395                         (BindingTypes.IDENTIFIABLE_ITEM, parent)));
396             } else {
397                 it.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
398                         (BindingTypes.ITEM, parent)));
399             }
400         }
401
402         if (!(schemaNode instanceof GroupingDefinition)) {
403             it.addImplementsType(BindingTypes.augmentable(it));
404         }
405
406         if (schemaNode instanceof DataNodeContainer) {
407             //TODO: design decomposition and implement it
408             //groupingsToGenTypes(module, ((DataNodeContainer) schemaNode).getGroupings());
409             it = addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it, genCtx);
410         }
411
412         return it;
413     }
414
415     static GeneratedTypeBuilder resolveNotification(final GeneratedTypeBuilder listenerInterface, String
416             parentName, final String basePackageName, final NotificationDefinition notification, final Module module,
417             final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String, GeneratedTypeBuilder>>
418             genTypeBuilders, TypeProvider typeProvider, Map<Module, ModuleContext> genCtx) {
419
420         processUsesAugments(schemaContext, notification, module, genCtx, genTypeBuilders,
421                 verboseClassComments, typeProvider);
422
423         final GeneratedTypeBuilder notificationInterface = addDefaultInterfaceDefinition
424                 (basePackageName, notification, null, module, genCtx, schemaContext,
425                         verboseClassComments, genTypeBuilders);
426         annotateDeprecatedIfNecessary(notification.getStatus(), notificationInterface);
427         notificationInterface.addImplementsType(NOTIFICATION);
428         genCtx.get(module).addChildNodeType(notification, notificationInterface);
429
430         // Notification object
431         resolveDataSchemaNodes(module, basePackageName, notificationInterface,
432                 notificationInterface, notification.getChildNodes(), genCtx, schemaContext,
433                 verboseClassComments, genTypeBuilders, typeProvider);
434
435         //in case of tied notification, incorporate parent's localName
436         final StringBuilder sb = new StringBuilder("on_");
437         if (parentName != null) {
438             sb.append(parentName).append('_');
439         }
440         sb.append(notificationInterface.getName());
441
442         listenerInterface.addMethod(JavaIdentifierNormalizer.normalizeSpecificIdentifier(sb.toString(), JavaIdentifier.METHOD))
443                 .setAccessModifier(AccessModifier.PUBLIC).addParameter(notificationInterface, "notification")
444                 .setComment(encodeAngleBrackets(notification.getDescription())).setReturnType(Types.VOID);
445         return listenerInterface;
446     }
447
448     /**
449      * Returns reference to generated type builder for specified
450      * <code>schemaNode</code> with <code>packageName</code>.
451      *
452      * Firstly the generated type builder is searched in
453      * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
454      * found it is created and added to <code>genTypeBuilders</code>.
455      *
456      * @param packageName
457      *            string with the package name to which returning generated type
458      *            builder belongs
459      * @param schemaNode
460      *            schema node which provide data about the schema node name
461      * @param schemaContext
462      * @param prefix
463      *            return type name prefix
464      * @return generated type builder for <code>schemaNode</code>
465      * @throws IllegalArgumentException
466      *             <ul>
467      *             <li>if <code>schemaNode</code> is null</li>
468      *             <li>if <code>packageName</code> is null</li>
469      *             <li>if QName of schema node is null</li>
470      *             <li>if schemaNode name is null</li>
471      *             </ul>
472      *
473      */
474     static GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
475                        final SchemaContext schemaContext, final String prefix, final boolean verboseClassComments,
476                        final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders) {
477
478         Preconditions.checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
479         Preconditions.checkArgument(packageName != null, "Package Name for Generated Type cannot be NULL.");
480         String schemaNodeName = schemaNode.getQName().getLocalName();
481         Preconditions.checkArgument(schemaNodeName != null, "Local Name of QName for Data Schema Node cannot be NULL.");
482
483         if (prefix != null && !prefix.isEmpty()) {
484             // underscore used as separator for distinction of class name parts
485             schemaNodeName = new StringBuilder(prefix).append('_').append(schemaNodeName).toString();
486         }
487
488         final GeneratedTypeBuilderImpl newType = new GeneratedTypeBuilderImpl(packageName, schemaNodeName);
489         final Module module = SchemaContextUtil.findParentModule(schemaContext, schemaNode);
490         qNameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
491         newType.addComment(schemaNode.getDescription());
492         newType.setDescription(createDescription(schemaNode, newType.getFullyQualifiedName(), schemaContext, verboseClassComments));
493         newType.setReference(schemaNode.getReference());
494         newType.setSchemaPath((List<QName>) schemaNode.getPath().getPathFromRoot());
495         newType.setModuleName(module.getName());
496
497         if (!genTypeBuilders.containsKey(packageName)) {
498             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
499             builders.put(newType.getName(), newType);
500             genTypeBuilders.put(packageName, builders);
501         } else {
502             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
503             if (!builders.containsKey(newType.getName())) {
504                 builders.put(newType.getName(), newType);
505             }
506         }
507         return newType;
508
509     }
510
511     private static void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode node,
512         final GeneratedTypeBuilder typeBuilder, final GeneratedTypeBuilder childOf, final Module module,
513         final Map<Module, ModuleContext> genCtx, final SchemaContext schemaContext, final boolean verboseClassComments,
514         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
515         //TODO: implement rest of schema nodes GTO building
516         if (node != null && typeBuilder != null) {
517             if (node instanceof ContainerSchemaNode) {
518                 containerToGenType(module, basePackageName, typeBuilder, childOf, (ContainerSchemaNode) node,
519                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
520             } else if (node instanceof LeafSchemaNode) {
521                 resolveLeafSchemaNodeAsMethod(schemaContext, typeBuilder, genCtx, (LeafSchemaNode) node, module,
522                         typeProvider);
523             } else if (node instanceof ListSchemaNode) {
524                 listToGenType(module, basePackageName, typeBuilder, childOf, (ListSchemaNode) node, schemaContext,
525                         verboseClassComments, genCtx, genTypeBuilders, typeProvider);
526             }
527         }
528
529     }
530
531     private static void containerToGenType(final Module module, final String basePackageName,
532         final GeneratedTypeBuilder parent, final GeneratedTypeBuilder childOf, final ContainerSchemaNode node,
533         final SchemaContext schemaContext, final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
534         final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
535
536         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
537                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
538         if (genType != null) {
539             constructGetter(parent, node.getQName().getLocalName(), node.getDescription(), genType, node.getStatus());
540             resolveDataSchemaNodes(module, basePackageName, genType, genType, node.getChildNodes(), genCtx,
541                     schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
542         }
543     }
544
545     private static void listToGenType(final Module module, final String basePackageName, final GeneratedTypeBuilder
546             parent, final GeneratedTypeBuilder childOf, final ListSchemaNode node, final SchemaContext schemaContext,
547             final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx,
548             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
549         final GeneratedTypeBuilder genType = processDataSchemaNode(module, basePackageName, childOf, node,
550                 schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
551         if (genType != null) {
552             final String nodeName = node.getQName().getLocalName();
553             constructGetter(parent, nodeName, node.getDescription(),
554                     Types.listTypeFor(genType), node.getStatus());
555             final List<QName> listKeys = node.getKeyDefinition();
556             final String packageName = new StringBuilder(packageNameForGeneratedType(basePackageName, node.getPath(),
557                     BindingNamespaceType.Key)).append('.').append(nodeName).toString();
558
559             final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, node);
560
561             for (final DataSchemaNode schemaNode : node.getChildNodes()) {
562                 if (!schemaNode.isAugmenting()) {
563                     addSchemaNodeToListBuilders(nodeName, basePackageName, schemaNode, genType, genTOBuilder, listKeys,
564                             module, typeProvider, schemaContext, genCtx, genTypeBuilders, verboseClassComments);
565                 }
566             }
567
568             // serialVersionUID
569             if (genTOBuilder != null) {
570                 final GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
571                 prop.setValue(Long.toString(computeDefaultSUID(genTOBuilder)));
572                 genTOBuilder.setSUID(prop);
573             }
574
575             typeBuildersToGenTypes(module, genType, genTOBuilder, genCtx);
576         }
577     }
578
579     private static void typeBuildersToGenTypes(final Module module, final GeneratedTypeBuilder typeBuilder,
580             final GeneratedTOBuilder genTOBuilder, final Map<Module, ModuleContext> genCtx) {
581         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
582         if (genTOBuilder != null) {
583             final GeneratedTransferObject genTO = genTOBuilder.toInstance();
584             constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO, Status.CURRENT);
585             genCtx.get(module).addGeneratedTOBuilder(genTOBuilder);
586         }
587     }
588
589     /**
590      * Converts <code>leaf</code> to the getter method which is added to
591      * <code>typeBuilder</code>.
592      *
593      * @param typeBuilder
594      *            generated type builder to which is added getter method as
595      *            <code>leaf</code> mapping
596      * @param leaf
597      *            leaf schema node which is mapped as getter method which is
598      *            added to <code>typeBuilder</code>
599      * @param module
600      *            Module in which type was defined
601      * @return boolean value
602      *         <ul>
603      *         <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
604      *         null</li>
605      *         <li>true - in other cases</li>
606      *         </ul>
607      */
608     private static Type resolveLeafSchemaNodeAsMethod(final SchemaContext schemaContext, final GeneratedTypeBuilder
609             typeBuilder, final Map<Module, ModuleContext> genCtx, final LeafSchemaNode leaf, final Module module,
610             final TypeProvider typeProvider) {
611         if (leaf == null || typeBuilder == null || leaf.isAddedByUses()) {
612             return null;
613         }
614
615         final String leafName = leaf.getQName().getLocalName();
616         if (leafName == null) {
617             return null;
618         }
619
620         final Module parentModule = findParentModule(schemaContext, leaf);
621         Type returnType = null;
622
623         final TypeDefinition<?> typeDef = leaf.getType();
624         if (isInnerType(leaf, typeDef)) {
625             if (typeDef instanceof EnumTypeDefinition) {
626                 returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf);
627                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) typeDef;
628                 final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leaf.getQName(),
629                         genCtx, typeBuilder, module);
630                 if (enumBuilder != null) {
631                     returnType = enumBuilder.toInstance(typeBuilder);
632                 }
633                 ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
634             } else if (typeDef instanceof UnionTypeDefinition) {
635                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
636                         typeProvider, schemaContext);
637                 if (genTOBuilder != null) {
638                     //TODO: https://bugs.opendaylight.org/show_bug.cgi?id=2289
639                     returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule, typeProvider);
640                 }
641             } else if (typeDef instanceof BitsTypeDefinition) {
642                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leaf, parentModule,
643                         typeProvider, schemaContext);
644                 if (genTOBuilder != null) {
645                     returnType = genTOBuilder.toInstance();
646                 }
647             } else {
648                 // It is constrained version of already declared type (inner declared type exists,
649                 // onlyfor special cases (Enum, Union, Bits), which were already checked.
650                 // In order to get proper class we need to look up closest derived type
651                 // and apply restrictions from leaf type
652                 final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
653                 returnType = typeProvider.javaTypeForSchemaDefinitionType(getBaseOrDeclaredType(typeDef), leaf,
654                         restrictions);
655             }
656         } else {
657             final Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);
658             returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, leaf, restrictions);
659         }
660
661         if (returnType == null) {
662             return null;
663         }
664
665         if (typeDef instanceof EnumTypeDefinition) {
666             ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
667         }
668
669         String leafDesc = leaf.getDescription();
670         if (leafDesc == null) {
671             leafDesc = "";
672         }
673
674         constructGetter(typeBuilder, leafName, leafDesc, returnType, leaf.getStatus());
675         genCtx.get(module).addChildNodeType(leaf, typeBuilder);
676         return returnType;
677     }
678
679     /**
680      * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
681      * or to <code>genTOBuilder</code> as property.
682      *
683      * @param nodeName
684      *            string contains the name of list
685      * @param basePackageName
686      *            string contains the module package name
687      * @param schemaNode
688      *            data schema node which should be added as getter method to
689      *            <code>typeBuilder</code> or as a property to
690      *            <code>genTOBuilder</code> if is part of the list key
691      * @param typeBuilder
692      *            generated type builder for the list schema node
693      * @param genTOBuilder
694      *            generated TO builder for the list keys
695      * @param listKeys
696      *            list of string which contains QNames of the list keys
697      * @param module
698      *            current module
699      * @param typeProvider
700      *            provider that defines contract for generated types
701      * @param schemaContext
702      *            schema context
703      * @param genCtx
704      *            map of generated entities in context of YANG modules
705      * @param genTypeBuilders
706      *            map of generated type builders
707      * @param verboseClassComments
708      *            generate verbose comments
709      * @throws IllegalArgumentException
710      *             <ul>
711      *             <li>if <code>schemaNode</code> equals null</li>
712      *             <li>if <code>typeBuilder</code> equals null</li>
713      *             </ul>
714      */
715     private static void addSchemaNodeToListBuilders(final String nodeName, final String basePackageName,
716             final DataSchemaNode schemaNode, final GeneratedTypeBuilder typeBuilder,
717             final GeneratedTOBuilder genTOBuilder, final List<QName> listKeys, final Module module,
718             final TypeProvider typeProvider, final SchemaContext schemaContext, final Map<Module, ModuleContext> genCtx,
719             final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final boolean verboseClassComments) {
720         checkArgument(schemaNode != null, "Data Schema Node cannot be NULL.");
721         checkArgument(typeBuilder != null, "Generated Type Builder cannot be NULL.");
722
723         if (schemaNode instanceof LeafSchemaNode) {
724             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
725             final QName leafQName = leaf.getQName();
726             final String leafName = leafQName.getLocalName();
727             String leafPckgName = basePackageName;
728             boolean isKeyPart = false;
729             if (listKeys.contains(leafQName)) {
730                 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Key).append('.')
731                         .append(nodeName).toString();
732                 isKeyPart = true;
733             } else {
734                 leafPckgName = new StringBuilder(leafPckgName).append('.').append(BindingNamespaceType.Data).append('.')
735                         .append(nodeName).toString();
736             }
737
738             final String leafGTOName = new StringBuilder(nodeName).append('_').append(leafName).toString();
739             final GeneratedTypeBuilder leafGTp = new GeneratedTypeBuilderImpl(leafPckgName, leafGTOName);
740             resolveLeafSchemaNodeAsMethod(schemaContext, leafGTp, genCtx, leaf, module,
741                     typeProvider);
742
743             constructGetter(typeBuilder, leafGTOName, schemaNode.getDescription(), leafGTp, Status.CURRENT);
744
745             if (isKeyPart) {
746                 AuxiliaryGenUtils.resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, leafGTp, true);
747             }
748         } else if (!schemaNode.isAddedByUses()) {
749             //TODO: implement leaf list to generated type
750             //TODO: implement choice to generated type
751             if (schemaNode instanceof ContainerSchemaNode) {
752                 containerToGenType(module, basePackageName, typeBuilder, typeBuilder, (ContainerSchemaNode) schemaNode,
753                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
754             } else if (schemaNode instanceof ListSchemaNode) {
755                 listToGenType(module, basePackageName, typeBuilder, typeBuilder, (ListSchemaNode) schemaNode,
756                         schemaContext, verboseClassComments, genCtx, genTypeBuilders, typeProvider);
757             }
758         }
759     }
760
761     private static TypeDefinition<?> getBaseOrDeclaredType(final TypeDefinition<?> typeDef) {
762         final TypeDefinition<?> baseType = typeDef.getBaseType();
763         return (baseType != null && baseType.getBaseType() != null) ? baseType : typeDef;
764     }
765
766     @SuppressWarnings({ "rawtypes", "unchecked" })
767     private static GeneratedTypeBuilder processDataSchemaNode(final Module module, final String basePackageName,
768         final GeneratedTypeBuilder childOf, final DataSchemaNode node, final SchemaContext schemaContext,
769         final boolean verboseClassComments, final Map<Module, ModuleContext> genCtx, final Map<String, Map<String,
770         GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
771
772         if (node.isAugmenting() || node.isAddedByUses()) {
773             return null;
774         }
775         final String packageName = packageNameForGeneratedType(basePackageName, node.getPath(), BindingNamespaceType.Data);
776         final GeneratedTypeBuilder genType = addDefaultInterfaceDefinition(packageName, node, childOf, module,
777                 genCtx, schemaContext, verboseClassComments, genTypeBuilders);
778         genType.addComment(node.getDescription());
779         annotateDeprecatedIfNecessary(node.getStatus(), genType);
780         genType.setDescription(createDescription(node, genType.getFullyQualifiedName(), schemaContext, verboseClassComments));
781         genType.setModuleName(module.getName());
782         genType.setReference(node.getReference());
783         genType.setSchemaPath((List) node.getPath().getPathFromRoot());
784         if (node instanceof DataNodeContainer) {
785             genCtx.get(module).addChildNodeType(node, genType);
786             //TODO: implement groupings to GTO building first
787             // groupingsToGenTypes(module, ((DataNodeContainer) node).getGroupings());
788             processUsesAugments(schemaContext, (DataNodeContainer) node, module, genCtx, genTypeBuilders,
789                     verboseClassComments, typeProvider);
790         }
791         return genType;
792     }
793 }