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