Refactored base yang-java types.
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingGeneratorImpl.java
1 /*
2  * Copyright (c) 2013 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 package org.opendaylight.yangtools.sal.binding.generator.impl;
9
10 import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;
11 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
12
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Comparator;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.concurrent.Future;
21
22 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
23 import org.opendaylight.yangtools.binding.generator.util.Types;
24 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
25 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
26 import org.opendaylight.yangtools.sal.binding.generator.api.BindingGenerator;
27 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
28 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject;
29 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
30 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
31 import org.opendaylight.yangtools.sal.binding.model.api.Type;
32 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder;
33 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
34 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
35 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
36 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
37 import org.opendaylight.yangtools.sal.binding.yang.types.GroupingDefinitionDependencySort;
38 import org.opendaylight.yangtools.sal.binding.yang.types.TypeProviderImpl;
39 import org.opendaylight.yangtools.yang.binding.DataRoot;
40 import org.opendaylight.yangtools.yang.binding.Identifiable;
41 import org.opendaylight.yangtools.yang.binding.Identifier;
42 import org.opendaylight.yangtools.yang.binding.RpcService;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.common.RpcResult;
45 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
46 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
47 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
48 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
50 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
52 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
56 import org.opendaylight.yangtools.yang.model.api.Module;
57 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
58 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
59 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
60 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
61 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
62 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
63 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
64 import org.opendaylight.yangtools.yang.model.api.UsesNode;
65 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
66 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
67 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
68 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
69 import org.opendaylight.yangtools.yang.model.util.DataNodeIterator;
70 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
71 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
72 import org.opendaylight.yangtools.yang.model.util.UnionType;
73
74 public final class BindingGeneratorImpl implements BindingGenerator {
75
76     /**
77      * Outter key represents the package name. Outter value represents map of
78      * all builders in the same package. Inner key represents the schema node
79      * name (in JAVA class/interface name format). Inner value represents
80      * instance of builder for schema node specified in key part.
81      */
82     private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
83
84     /**
85      * Provide methods for converting YANG types to JAVA types.
86      */
87     private TypeProvider typeProvider;
88
89     /**
90      * Holds reference to schema context to resolve data of augmented elemnt
91      * when creating augmentation builder
92      */
93     private SchemaContext schemaContext;
94
95     /**
96      * Each grouping which is converted from schema node to generated type is
97      * added to this map with its Schema path as key to make it easier to get
98      * reference to it. In schema nodes in <code>uses</code> attribute there is
99      * only Schema Path but when building list of implemented interfaces for
100      * Schema node the object of type <code>Type</code> is required. So in this
101      * case is used this map.
102      */
103     private final Map<SchemaPath, GeneratedType> allGroupings = new HashMap<SchemaPath, GeneratedType>();
104
105     /**
106      * Only parent constructor is invoked.
107      */
108
109     private final static String YANG_EXT_NAMESPACE = "urn:opendaylight:yang:extension:yang-ext";
110     private final static String AUGMENT_IDENTIFIER_NAME = "augment-identifier";
111
112     public BindingGeneratorImpl() {
113         super();
114     }
115
116     /**
117      * Resolves generated types from <code>context</code> schema nodes of all
118      * modules.
119      *
120      * Generated types are created for modules, groupings, types, containers,
121      * lists, choices, augments, rpcs, notification, identities.
122      *
123      * @param context
124      *            schema context which contains data about all schema nodes
125      *            saved in modules
126      * @return list of types (usually <code>GeneratedType</code>
127      *         <code>GeneratedTransferObject</code>which are generated from
128      *         <code>context</code> data.
129      * @throws IllegalArgumentException
130      *             if param <code>context</code> is null
131      * @throws IllegalStateException
132      *             if <code>context</code> contain no modules
133      */
134     @Override
135     public List<Type> generateTypes(final SchemaContext context) {
136         if (context == null) {
137             throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
138         }
139         if (context.getModules() == null) {
140             throw new IllegalStateException("Schema Context does not contain defined modules!");
141         }
142
143         final List<Type> generatedTypes = new ArrayList<>();
144         schemaContext = context;
145         typeProvider = new TypeProviderImpl(context);
146         final Set<Module> modules = context.getModules();
147         genTypeBuilders = new HashMap<>();
148         for (final Module module : modules) {
149
150             generatedTypes.addAll(allGroupingsToGenTypes(module));
151
152             if (false == module.getChildNodes().isEmpty()) {
153                 generatedTypes.add(moduleToDataType(module));
154             }
155             generatedTypes.addAll(allTypeDefinitionsToGenTypes(module));
156             generatedTypes.addAll(allContainersToGenTypes(module));
157             generatedTypes.addAll(allListsToGenTypes(module));
158             generatedTypes.addAll(allChoicesToGenTypes(module));
159             generatedTypes.addAll(allAugmentsToGenTypes(module));
160             generatedTypes.addAll(allRPCMethodsToGenType(module));
161             generatedTypes.addAll(allNotificationsToGenType(module));
162             generatedTypes.addAll(allIdentitiesToGenTypes(module, context));
163
164         }
165         return generatedTypes;
166     }
167
168     /**
169      * Resolves generated types from <code>context</code> schema nodes only for
170      * modules specified in <code>modules</code>
171      *
172      * Generated types are created for modules, groupings, types, containers,
173      * lists, choices, augments, rpcs, notification, identities.
174      *
175      * @param context
176      *            schema context which contains data about all schema nodes
177      *            saved in modules
178      * @param modules
179      *            set of modules for which schema nodes should be generated
180      *            types
181      * @return list of types (usually <code>GeneratedType</code> or
182      *         <code>GeneratedTransferObject</code>) which:
183      *         <ul>
184      *         <li>are generated from <code>context</code> schema nodes and</li>
185      *         <li>are also part of some of the module in <code>modules</code>
186      *         set</li>.
187      *         </ul>
188      * @throws IllegalArgumentException
189      *             <ul>
190      *             <li>if param <code>context</code> is null or</li>
191      *             <li>if param <code>modules</code> is null</li>
192      *             </ul>
193      * @throws IllegalStateException
194      *             if <code>context</code> contain no modules
195      */
196     @Override
197     public List<Type> generateTypes(final SchemaContext context, final Set<Module> modules) {
198         if (context == null) {
199             throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
200         }
201         if (context.getModules() == null) {
202             throw new IllegalStateException("Schema Context does not contain defined modules!");
203         }
204         if (modules == null) {
205             throw new IllegalArgumentException("Sef of Modules cannot be NULL!");
206         }
207
208         final List<Type> filteredGenTypes = new ArrayList<>();
209         schemaContext = context;
210         typeProvider = new TypeProviderImpl(context);
211         final Set<Module> contextModules = context.getModules();
212         genTypeBuilders = new HashMap<>();
213         for (final Module contextModule : contextModules) {
214             final List<Type> generatedTypes = new ArrayList<>();
215
216             generatedTypes.addAll(allGroupingsToGenTypes(contextModule));
217             if (false == contextModule.getChildNodes().isEmpty()) {
218                 generatedTypes.add(moduleToDataType(contextModule));
219             }
220             generatedTypes.addAll(allTypeDefinitionsToGenTypes(contextModule));
221             generatedTypes.addAll(allContainersToGenTypes(contextModule));
222             generatedTypes.addAll(allListsToGenTypes(contextModule));
223             generatedTypes.addAll(allChoicesToGenTypes(contextModule));
224             generatedTypes.addAll(allAugmentsToGenTypes(contextModule));
225             generatedTypes.addAll(allRPCMethodsToGenType(contextModule));
226             generatedTypes.addAll(allNotificationsToGenType(contextModule));
227             generatedTypes.addAll(allIdentitiesToGenTypes(contextModule, context));
228
229             if (modules.contains(contextModule)) {
230                 filteredGenTypes.addAll(generatedTypes);
231             }
232         }
233         return filteredGenTypes;
234     }
235
236     /**
237      * Converts all extended type definitions of module to the list of
238      * <code>Type</code> objects.
239      *
240      * @param module
241      *            module from which is obtained set of type definitions
242      * @return list of <code>Type</code> which are generated from extended
243      *         definition types (object of type <code>ExtendedType</code>)
244      * @throws IllegalArgumentException
245      *             <ul>
246      *             <li>if module equals null</li>
247      *             <li>if name of module equals null</li>
248      *             <li>if type definitions of module equal null</li>
249      *             </ul>
250      *
251      */
252     private List<Type> allTypeDefinitionsToGenTypes(final Module module) {
253         if (module == null) {
254             throw new IllegalArgumentException("Module reference cannot be NULL!");
255         }
256         if (module.getName() == null) {
257             throw new IllegalArgumentException("Module name cannot be NULL!");
258         }
259         if (module.getTypeDefinitions() == null) {
260             throw new IllegalArgumentException("Type Definitions for module " + module.getName() + " cannot be NULL!");
261         }
262
263         final Set<TypeDefinition<?>> typeDefinitions = module.getTypeDefinitions();
264         final List<Type> generatedTypes = new ArrayList<>();
265         for (final TypeDefinition<?> typedef : typeDefinitions) {
266             if (typedef != null) {
267                 final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef);
268                 if ((type != null) && !generatedTypes.contains(type)) {
269                     generatedTypes.add(type);
270                 }
271             }
272         }
273         return generatedTypes;
274     }
275
276     /**
277      * Converts all <b>containers</b> of the module to the list of
278      * <code>Type</code> objects.
279      *
280      * @param module
281      *            module from which is obtained DataNodeIterator to iterate over
282      *            all containers
283      * @return list of <code>Type</code> which are generated from containers
284      *         (objects of type <code>ContainerSchemaNode</code>)
285      * @throws IllegalArgumentException
286      *             <ul>
287      *             <li>if the module equals null</li>
288      *             <li>if the name of module equals null</li>
289      *             <li>if the set of child nodes equals null</li>
290      *             </ul>
291      *
292      */
293     private List<Type> allContainersToGenTypes(final Module module) {
294         if (module == null) {
295             throw new IllegalArgumentException("Module reference cannot be NULL!");
296         }
297
298         if (module.getName() == null) {
299             throw new IllegalArgumentException("Module name cannot be NULL!");
300         }
301
302         if (module.getChildNodes() == null) {
303             throw new IllegalArgumentException("Reference to Set of Child Nodes in module " + module.getName()
304                     + " cannot be NULL!");
305         }
306
307         final List<Type> generatedTypes = new ArrayList<>();
308         final DataNodeIterator it = new DataNodeIterator(module);
309         final List<ContainerSchemaNode> schemaContainers = it.allContainers();
310         final String basePackageName = moduleNamespaceToPackageName(module);
311         for (final ContainerSchemaNode container : schemaContainers) {
312             if (!container.isAddedByUses()) {
313                 generatedTypes.add(containerToGenType(basePackageName, container));
314             }
315         }
316         return generatedTypes;
317     }
318
319     /**
320      * Converts all <b>lists</b> of the module to the list of <code>Type</code>
321      * objects.
322      *
323      * @param module
324      *            module from which is obtained DataNodeIterator to iterate over
325      *            all lists
326      * @return list of <code>Type</code> which are generated from lists (objects
327      *         of type <code>ListSchemaNode</code>)
328      * @throws IllegalArgumentException
329      *             <ul>
330      *             <li>if the module equals null</li>
331      *             <li>if the name of module equals null</li>
332      *             <li>if the set of child nodes equals null</li>
333      *             </ul>
334      *
335      */
336     private List<Type> allListsToGenTypes(final Module module) {
337         if (module == null) {
338             throw new IllegalArgumentException("Module reference cannot be NULL!");
339         }
340
341         if (module.getName() == null) {
342             throw new IllegalArgumentException("Module name cannot be NULL!");
343         }
344
345         if (module.getChildNodes() == null) {
346             throw new IllegalArgumentException("Reference to Set of Child Nodes in module " + module.getName()
347                     + " cannot be NULL!");
348         }
349
350         final List<Type> generatedTypes = new ArrayList<>();
351         final DataNodeIterator it = new DataNodeIterator(module);
352         final List<ListSchemaNode> schemaLists = it.allLists();
353         final String basePackageName = moduleNamespaceToPackageName(module);
354         if (schemaLists != null) {
355             for (final ListSchemaNode list : schemaLists) {
356                 if (!list.isAddedByUses()) {
357                     generatedTypes.addAll(listToGenType(basePackageName, list));
358                 }
359             }
360         }
361         return generatedTypes;
362     }
363
364     /**
365      * Converts all <b>choices</b> of the module to the list of
366      * <code>Type</code> objects.
367      *
368      * @param module
369      *            module from which is obtained DataNodeIterator to iterate over
370      *            all choices
371      * @return list of <code>Type</code> which are generated from choices
372      *         (objects of type <code>ChoiceNode</code>)
373      * @throws IllegalArgumentException
374      *             <ul>
375      *             <li>if the module equals null</li>
376      *             <li>if the name of module equals null</li> *
377      *             </ul>
378      *
379      */
380     private List<GeneratedType> allChoicesToGenTypes(final Module module) {
381         if (module == null) {
382             throw new IllegalArgumentException("Module reference cannot be NULL!");
383         }
384         if (module.getName() == null) {
385             throw new IllegalArgumentException("Module name cannot be NULL!");
386         }
387
388         final DataNodeIterator it = new DataNodeIterator(module);
389         final List<ChoiceNode> choiceNodes = it.allChoices();
390         final String basePackageName = moduleNamespaceToPackageName(module);
391
392         final List<GeneratedType> generatedTypes = new ArrayList<>();
393         for (final ChoiceNode choice : choiceNodes) {
394             if ((choice != null) && !choice.isAddedByUses()) {
395                 generatedTypes.addAll(choiceToGeneratedType(basePackageName, choice));
396             }
397         }
398         return generatedTypes;
399     }
400
401     /**
402      * Converts all <b>augmentation</b> of the module to the list
403      * <code>Type</code> objects.
404      *
405      * @param module
406      *            module from which is obtained list of all augmentation objects
407      *            to iterate over them
408      * @return list of <code>Type</code> which are generated from augments
409      *         (objects of type <code>AugmentationSchema</code>)
410      * @throws IllegalArgumentException
411      *             <ul>
412      *             <li>if the module equals null</li>
413      *             <li>if the name of module equals null</li>
414      *             <li>if the set of child nodes equals null</li>
415      *             </ul>
416      *
417      */
418     private List<Type> allAugmentsToGenTypes(final Module module) {
419         if (module == null) {
420             throw new IllegalArgumentException("Module reference cannot be NULL!");
421         }
422         if (module.getName() == null) {
423             throw new IllegalArgumentException("Module name cannot be NULL!");
424         }
425         if (module.getChildNodes() == null) {
426             throw new IllegalArgumentException("Reference to Set of Augmentation Definitions in module "
427                     + module.getName() + " cannot be NULL!");
428         }
429
430         final List<Type> generatedTypes = new ArrayList<>();
431         final String basePackageName = moduleNamespaceToPackageName(module);
432         final List<AugmentationSchema> augmentations = resolveAugmentations(module);
433         for (final AugmentationSchema augment : augmentations) {
434             generatedTypes.addAll(augmentationToGenTypes(basePackageName, augment));
435         }
436         return generatedTypes;
437     }
438
439     /**
440      * Returns list of <code>AugmentationSchema</code> objects. The objects are
441      * sorted according to the length of their target path from the shortest to
442      * the longest.
443      *
444      * @param module
445      *            module from which is obtained list of all augmentation objects
446      * @return list of sorted <code>AugmentationSchema</code> objects obtained
447      *         from <code>module</code>
448      * @throws IllegalArgumentException
449      *             <ul>
450      *             <li>if the module equals null</li>
451      *             <li>if the set of augmentation equals null</li>
452      *             </ul>
453      *
454      */
455     private List<AugmentationSchema> resolveAugmentations(final Module module) {
456         if (module == null) {
457             throw new IllegalArgumentException("Module reference cannot be NULL!");
458         }
459         if (module.getAugmentations() == null) {
460             throw new IllegalStateException("Augmentations Set cannot be NULL!");
461         }
462
463         final Set<AugmentationSchema> augmentations = module.getAugmentations();
464         final List<AugmentationSchema> sortedAugmentations = new ArrayList<>(augmentations);
465         Collections.sort(sortedAugmentations, new Comparator<AugmentationSchema>() {
466
467             @Override
468             public int compare(AugmentationSchema augSchema1, AugmentationSchema augSchema2) {
469
470                 if (augSchema1.getTargetPath().getPath().size() > augSchema2.getTargetPath().getPath().size()) {
471                     return 1;
472                 } else if (augSchema1.getTargetPath().getPath().size() < augSchema2.getTargetPath().getPath().size()) {
473                     return -1;
474                 }
475                 return 0;
476
477             }
478         });
479
480         return sortedAugmentations;
481     }
482
483     /**
484      * Converts whole <b>module</b> to <code>GeneratedType</code> object.
485      * Firstly is created the module builder object from which is finally
486      * obtained reference to <code>GeneratedType</code> object.
487      *
488      * @param module
489      *            module from which are obtained the module name, child nodes,
490      *            uses and is derived package name
491      * @return <code>GeneratedType</code> which is internal representation of
492      *         the module
493      * @throws IllegalArgumentException
494      *             if the module equals null
495      *
496      */
497     private GeneratedType moduleToDataType(final Module module) {
498         if (module == null) {
499             throw new IllegalArgumentException("Module reference cannot be NULL!");
500         }
501
502         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
503         addImplementedInterfaceFromUses(module, moduleDataTypeBuilder);
504         moduleDataTypeBuilder.addImplementsType(Types.typeForClass(DataRoot.class));
505
506         final String basePackageName = moduleNamespaceToPackageName(module);
507         if (moduleDataTypeBuilder != null) {
508             final Set<DataSchemaNode> dataNodes = module.getChildNodes();
509             resolveDataSchemaNodes(basePackageName, moduleDataTypeBuilder, dataNodes);
510         }
511         return moduleDataTypeBuilder.toInstance();
512     }
513
514     /**
515      * Converts all <b>rpcs</b> inputs and outputs substatements of the module
516      * to the list of <code>Type</code> objects. In addition are to containers
517      * and lists which belong to input or output also part of returning list.
518      *
519      * @param module
520      *            module from which is obtained set of all rpc objects to
521      *            iterate over them
522      * @return list of <code>Type</code> which are generated from rpcs inputs,
523      *         outputs + container and lists which are part of inputs or outputs
524      * @throws IllegalArgumentException
525      *             <ul>
526      *             <li>if the module equals null</li>
527      *             <li>if the name of module equals null</li>
528      *             <li>if the set of child nodes equals null</li>
529      *             </ul>
530      *
531      */
532     private List<Type> allRPCMethodsToGenType(final Module module) {
533         if (module == null) {
534             throw new IllegalArgumentException("Module reference cannot be NULL!");
535         }
536
537         if (module.getName() == null) {
538             throw new IllegalArgumentException("Module name cannot be NULL!");
539         }
540
541         if (module.getChildNodes() == null) {
542             throw new IllegalArgumentException("Reference to Set of RPC Method Definitions in module "
543                     + module.getName() + " cannot be NULL!");
544         }
545
546         final String basePackageName = moduleNamespaceToPackageName(module);
547         final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
548
549         if (rpcDefinitions.isEmpty()) {
550             return Collections.emptyList();
551         }
552
553         final List<Type> genRPCTypes = new ArrayList<>();
554         final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
555         interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
556         final Type future = Types.typeForClass(Future.class);
557         for (final RpcDefinition rpc : rpcDefinitions) {
558             if (rpc != null) {
559
560                 String rpcName = parseToClassName(rpc.getQName().getLocalName());
561                 String rpcMethodName = parseToValidParamName(rpcName);
562                 MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
563
564                 final List<DataNodeIterator> rpcInOut = new ArrayList<>();
565
566                 ContainerSchemaNode input = rpc.getInput();
567                 ContainerSchemaNode output = rpc.getOutput();
568
569                 if (input != null) {
570                     rpcInOut.add(new DataNodeIterator(input));
571                     GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
572                     addImplementedInterfaceFromUses(input, inType);
573                     inType.addImplementsType(Types.DATA_OBJECT);
574                     resolveDataSchemaNodes(basePackageName, inType, input.getChildNodes());
575                     Type inTypeInstance = inType.toInstance();
576                     genRPCTypes.add(inTypeInstance);
577                     method.addParameter(inTypeInstance, "input");
578                 }
579
580                 Type outTypeInstance = Types.typeForClass(Void.class);
581                 if (output != null) {
582                     rpcInOut.add(new DataNodeIterator(output));
583                     GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
584                     addImplementedInterfaceFromUses(output, outType);
585                     outType.addImplementsType(Types.DATA_OBJECT);
586                     resolveDataSchemaNodes(basePackageName, outType, output.getChildNodes());
587                     outTypeInstance = outType.toInstance();
588                     genRPCTypes.add(outTypeInstance);
589
590                 }
591
592                 final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
593                 method.setReturnType(Types.parameterizedTypeFor(future, rpcRes));
594                 for (DataNodeIterator it : rpcInOut) {
595                     List<ContainerSchemaNode> nContainers = it.allContainers();
596                     if ((nContainers != null) && !nContainers.isEmpty()) {
597                         for (final ContainerSchemaNode container : nContainers) {
598                             if (!container.isAddedByUses()) {
599                                 genRPCTypes.add(containerToGenType(basePackageName, container));
600                             }
601                         }
602                     }
603                     List<ListSchemaNode> nLists = it.allLists();
604                     if ((nLists != null) && !nLists.isEmpty()) {
605                         for (final ListSchemaNode list : nLists) {
606                             if (!list.isAddedByUses()) {
607                                 genRPCTypes.addAll(listToGenType(basePackageName, list));
608                             }
609                         }
610                     }
611                 }
612             }
613         }
614         genRPCTypes.add(interfaceBuilder.toInstance());
615         return genRPCTypes;
616     }
617
618     /**
619      * Converts all <b>notifications</b> of the module to the list of
620      * <code>Type</code> objects. In addition are to this list added containers
621      * and lists which are part of this notification.
622      *
623      * @param module
624      *            module from which is obtained set of all notification objects
625      *            to iterate over them
626      * @return list of <code>Type</code> which are generated from notification
627      *         (object of type <code>NotificationDefinition</code>
628      * @throws IllegalArgumentException
629      *             <ul>
630      *             <li>if the module equals null</li>
631      *             <li>if the name of module equals null</li>
632      *             <li>if the set of child nodes equals null</li>
633      *             </ul>
634      *
635      */
636     private List<Type> allNotificationsToGenType(final Module module) {
637         if (module == null) {
638             throw new IllegalArgumentException("Module reference cannot be NULL!");
639         }
640
641         if (module.getName() == null) {
642             throw new IllegalArgumentException("Module name cannot be NULL!");
643         }
644
645         if (module.getChildNodes() == null) {
646             throw new IllegalArgumentException("Reference to Set of Notification Definitions in module "
647                     + module.getName() + " cannot be NULL!");
648         }
649
650         final String basePackageName = moduleNamespaceToPackageName(module);
651         final List<Type> genNotifyTypes = new ArrayList<>();
652         final Set<NotificationDefinition> notifications = module.getNotifications();
653
654         for (final NotificationDefinition notification : notifications) {
655             if (notification != null) {
656                 DataNodeIterator it = new DataNodeIterator(notification);
657
658                 // Containers
659                 for (ContainerSchemaNode node : it.allContainers()) {
660                     if (!node.isAddedByUses()) {
661                         genNotifyTypes.add(containerToGenType(basePackageName, node));
662                     }
663                 }
664                 // Lists
665                 for (ListSchemaNode node : it.allLists()) {
666                     if (!node.isAddedByUses()) {
667                         genNotifyTypes.addAll(listToGenType(basePackageName, node));
668                     }
669                 }
670                 final GeneratedTypeBuilder notificationTypeBuilder = addDefaultInterfaceDefinition(basePackageName,
671                         notification);
672                 notificationTypeBuilder.addImplementsType(Types
673                         .typeForClass(org.opendaylight.yangtools.yang.binding.Notification.class));
674                 // Notification object
675                 resolveDataSchemaNodes(basePackageName, notificationTypeBuilder, notification.getChildNodes());
676                 genNotifyTypes.add(notificationTypeBuilder.toInstance());
677             }
678         }
679         return genNotifyTypes;
680     }
681
682     /**
683      * Converts all <b>identities</b> of the module to the list of
684      * <code>Type</code> objects.
685      *
686      * @param module
687      *            module from which is obtained set of all identity objects to
688      *            iterate over them
689      * @param context
690      *            schema context only used as input parameter for method
691      *            {@link identityToGenType}
692      * @return list of <code>Type</code> which are generated from identities
693      *         (object of type <code>IdentitySchemaNode</code>
694      *
695      */
696     private List<Type> allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
697         List<Type> genTypes = new ArrayList<>();
698
699         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
700
701         final String basePackageName = moduleNamespaceToPackageName(module);
702
703         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
704             for (final IdentitySchemaNode identity : schemaIdentities) {
705                 genTypes.add(identityToGenType(basePackageName, identity, context));
706             }
707         }
708         return genTypes;
709     }
710
711     /**
712      * Converts the <b>identity</b> object to GeneratedType. Firstly it is
713      * created transport object builder. If identity contains base identity then
714      * reference to base identity is added to superior identity as its extend.
715      * If identity doesn't contain base identity then only reference to abstract
716      * class {@link org.opendaylight.yangtools.yang.model.api.BaseIdentity
717      * BaseIdentity} is added
718      *
719      * @param basePackageName
720      *            string contains the module package name
721      * @param identity
722      *            IdentitySchemaNode which contains data about identity
723      * @param context
724      *            SchemaContext which is used to get package and name
725      *            information about base of identity
726      *
727      * @return GeneratedType which is generated from identity (object of type
728      *         <code>IdentitySchemaNode</code>
729      *
730      */
731     private GeneratedType identityToGenType(final String basePackageName, final IdentitySchemaNode identity,
732             final SchemaContext context) {
733         if (identity == null) {
734             return null;
735         }
736
737         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
738         final String genTypeName = parseToClassName(identity.getQName().getLocalName());
739         final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
740
741         IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
742         if (baseIdentity != null) {
743             Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
744
745             final String returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
746             final String returnTypeName = parseToClassName(baseIdentity.getQName().getLocalName());
747
748             GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
749             newType.setExtendsType(gto);
750         } else {
751             newType.setExtendsType(Types.getBaseIdentityTO());
752         }
753         newType.setAbstract(true);
754         return newType.toInstance();
755     }
756
757     /**
758      * Converts all <b>groupings</b> of the module to the list of
759      * <code>Type</code> objects. Firstly are groupings sorted according mutual
760      * dependencies. At least dependend (indepedent) groupings are in the list
761      * saved at first positions. For every grouping the record is added to map
762      * {@link BindingGeneratorImpl#allGroupings allGroupings}
763      *
764      * @param module
765      *            module from which is obtained set of all grouping objects to
766      *            iterate over them
767      * @return list of <code>Type</code> which are generated from groupings
768      *         (object of type <code>GroupingDefinition</code>)
769      *
770      */
771     private List<Type> allGroupingsToGenTypes(final Module module) {
772         if (module == null) {
773             throw new IllegalArgumentException("Module parameter can not be null");
774         }
775         final List<Type> genTypes = new ArrayList<>();
776         final String basePackageName = moduleNamespaceToPackageName(module);
777         final Set<GroupingDefinition> groupings = module.getGroupings();
778         List<GroupingDefinition> groupingsSortedByDependencies;
779
780         groupingsSortedByDependencies = GroupingDefinitionDependencySort.sort(groupings);
781
782         for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
783             GeneratedType genType = groupingToGenType(basePackageName, grouping);
784             genTypes.add(genType);
785             SchemaPath schemaPath = grouping.getPath();
786             allGroupings.put(schemaPath, genType);
787         }
788         return genTypes;
789     }
790
791     /**
792      * Converts individual grouping to GeneratedType. Firstly generated type
793      * builder is created and every child node of grouping is resolved to the
794      * method.
795      *
796      * @param basePackageName
797      *            string contains the module package name
798      * @param grouping
799      *            GroupingDefinition which contains data about grouping
800      * @return GeneratedType which is generated from grouping (object of type
801      *         <code>GroupingDefinition</code>)
802      */
803     private GeneratedType groupingToGenType(final String basePackageName, GroupingDefinition grouping) {
804         if (grouping == null) {
805             return null;
806         }
807
808         final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath());
809         final Set<DataSchemaNode> schemaNodes = grouping.getChildNodes();
810         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, grouping);
811
812         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
813         return typeBuilder.toInstance();
814     }
815
816     /**
817      * Tries to find EnumTypeDefinition in <code>typeDefinition</code>. If base
818      * type of <code>typeDefinition</code> is of the type ExtendedType then this
819      * method is recursivelly called with this base type.
820      *
821      * @param typeDefinition
822      *            TypeDefinition in which should be EnumTypeDefinition found as
823      *            base type
824      * @return EnumTypeDefinition if it is found inside
825      *         <code>typeDefinition</code> or <code>null</code> in other case
826      */
827     private EnumTypeDefinition enumTypeDefFromExtendedType(final TypeDefinition<?> typeDefinition) {
828         if (typeDefinition != null) {
829             if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
830                 return (EnumTypeDefinition) typeDefinition.getBaseType();
831             } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
832                 return enumTypeDefFromExtendedType(typeDefinition.getBaseType());
833             }
834         }
835         return null;
836     }
837
838     /**
839      * Adds enumeration builder created from <code>enumTypeDef</code> to
840      * <code>typeBuilder</code>.
841      *
842      * Each <code>enumTypeDef</code> item is added to builder with its name and
843      * value.
844      *
845      * @param enumTypeDef
846      *            EnumTypeDefinition contains enum data
847      * @param enumName
848      *            string contains name which will be assigned to enumeration
849      *            builder
850      * @param typeBuilder
851      *            GeneratedTypeBuilder to which will be enum builder assigned
852      * @return enumeration builder which contais data from
853      *         <code>enumTypeDef</code>
854      */
855     private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final String enumName,
856             final GeneratedTypeBuilder typeBuilder) {
857         if ((enumTypeDef != null) && (typeBuilder != null) && (enumTypeDef.getQName() != null)
858                 && (enumTypeDef.getQName().getLocalName() != null)) {
859
860             final String enumerationName = parseToClassName(enumName);
861             final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
862
863             if (enumBuilder != null) {
864                 final List<EnumPair> enums = enumTypeDef.getValues();
865                 if (enums != null) {
866                     int listIndex = 0;
867                     for (final EnumPair enumPair : enums) {
868                         if (enumPair != null) {
869                             final String enumPairName = parseToClassName(enumPair.getName());
870                             Integer enumPairValue = enumPair.getValue();
871
872                             if (enumPairValue == null) {
873                                 enumPairValue = listIndex;
874                             }
875                             enumBuilder.addValue(enumPairName, enumPairValue);
876                             listIndex++;
877                         }
878                     }
879                 }
880                 return enumBuilder;
881             }
882         }
883         return null;
884     }
885
886     /**
887      * Generates type builder for <code>module</code>.
888      *
889      * @param module
890      *            Module which is source of package name for generated type
891      *            builder
892      * @param postfix
893      *            string which is added to the module class name representation
894      *            as suffix
895      * @return instance of GeneratedTypeBuilder which represents
896      *         <code>module</code>.
897      * @throws IllegalArgumentException
898      *             if <code>module</code> equals null
899      */
900     private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
901         if (module == null) {
902             throw new IllegalArgumentException("Module reference cannot be NULL!");
903         }
904         String packageName = moduleNamespaceToPackageName(module);
905         final String moduleName = parseToClassName(module.getName()) + postfix;
906
907         return new GeneratedTypeBuilderImpl(packageName, moduleName);
908
909     }
910
911     /**
912      * Converts <code>augSchema</code> to list of <code>Type</code> which
913      * contains generated type for augmentation. In addition there are also
914      * generated types for all containers, list and choices which are child of
915      * <code>augSchema</code> node or a generated types for cases are added if
916      * augmented node is choice.
917      *
918      * @param augmentPackageName
919      *            string with the name of the package to which the augmentation
920      *            belongs
921      * @param augSchema
922      *            AugmentationSchema which is contains data about agumentation
923      *            (target path, childs...)
924      * @return list of <code>Type</code> objects which contains generated type
925      *         for augmentation and for container, list and choice child nodes
926      * @throws IllegalArgumentException
927      *             <ul>
928      *             <li>if <code>augmentPackageName</code> equals null</li>
929      *             <li>if <code>augSchema</code> equals null</li>
930      *             <li>if target path of <code>augSchema</code> equals null</li>
931      *             </ul>
932      */
933     private List<Type> augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema) {
934         if (augmentPackageName == null) {
935             throw new IllegalArgumentException("Package Name cannot be NULL!");
936         }
937         if (augSchema == null) {
938             throw new IllegalArgumentException("Augmentation Schema cannot be NULL!");
939         }
940         if (augSchema.getTargetPath() == null) {
941             throw new IllegalStateException("Augmentation Schema does not contain Target Path (Target Path is NULL).");
942         }
943
944         final List<Type> genTypes = new ArrayList<>();
945
946         // EVERY augmented interface will extends Augmentation<T> interface
947         // and DataObject interface!!!
948         final SchemaPath targetPath = augSchema.getTargetPath();
949         final DataSchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
950         if ((targetSchemaNode != null) && (targetSchemaNode.getQName() != null)
951                 && (targetSchemaNode.getQName().getLocalName() != null)) {
952             final Module targetModule = findParentModule(schemaContext, targetSchemaNode);
953             final String targetBasePackage = moduleNamespaceToPackageName(targetModule);
954             final String targetPackageName = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());
955             final String targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();
956             final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
957
958             if (!(targetSchemaNode instanceof ChoiceNode)) {
959                 final GeneratedTypeBuilder augTypeBuilder = addRawAugmentGenTypeDefinition(augmentPackageName,
960                         targetPackageName, targetSchemaNodeName, augSchema);
961                 final GeneratedType augType = augTypeBuilder.toInstance();
962                 genTypes.add(augType);
963             } else {
964                 final Type refChoiceType = new ReferencedTypeImpl(targetPackageName,
965                         parseToClassName(targetSchemaNodeName));
966                 final ChoiceNode choiceTarget = (ChoiceNode) targetSchemaNode;
967                 final Set<ChoiceCaseNode> choiceCaseNodes = choiceTarget.getCases();
968                 genTypes.addAll(generateTypesFromAugmentedChoiceCases(augmentPackageName, refChoiceType,
969                         choiceCaseNodes));
970             }
971             genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes));
972         }
973         return genTypes;
974     }
975
976     /**
977      * Returns a generated type builder for an augmentation.
978      *
979      * The name of the type builder is equal to the name of augmented node with
980      * serial number as suffix.
981      *
982      * @param augmentPackageName
983      *            string with contains the package name to which the augment
984      *            belongs
985      * @param targetPackageName
986      *            string with the package name to which the augmented node
987      *            belongs
988      * @param targetSchemaNodeName
989      *            string with the name of the augmented node
990      * @param augSchema
991      *            augmentation schema which contains data about the child nodes
992      *            and uses of augment
993      * @return generated type builder for augment
994      */
995     private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final String augmentPackageName,
996             final String targetPackageName, final String targetSchemaNodeName, final AugmentationSchema augSchema) {
997         final String targetTypeName = parseToClassName(targetSchemaNodeName);
998         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
999         if (augmentBuilders == null) {
1000             augmentBuilders = new HashMap<>();
1001             genTypeBuilders.put(augmentPackageName, augmentBuilders);
1002         }
1003         final String augIdentifier = getAugmentIdentifier(augSchema.getUnknownSchemaNodes());
1004
1005         final String augTypeName = augIdentifier != null ? parseToClassName(augIdentifier) : augGenTypeName(
1006                 augmentBuilders, targetTypeName);
1007         final Type targetTypeRef = new ReferencedTypeImpl(targetPackageName, targetTypeName);
1008         final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
1009
1010         final GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
1011
1012         augTypeBuilder.addImplementsType(Types.DATA_OBJECT);
1013         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
1014         addImplementedInterfaceFromUses(augSchema, augTypeBuilder);
1015
1016         augSchemaNodeToMethods(augmentPackageName, augTypeBuilder, augChildNodes);
1017         augmentBuilders.put(augTypeName, augTypeBuilder);
1018         return augTypeBuilder;
1019     }
1020
1021     private String getAugmentIdentifier(List<UnknownSchemaNode> unknownSchemaNodes) {
1022         String ret = null;
1023         for (UnknownSchemaNode unknownSchemaNode : unknownSchemaNodes) {
1024             QName nodeType = unknownSchemaNode.getNodeType();
1025             if (AUGMENT_IDENTIFIER_NAME.equals(nodeType.getLocalName())
1026                     && YANG_EXT_NAMESPACE.equals(nodeType.getNamespace().toString())) {
1027                 return unknownSchemaNode.getNodeParameter();
1028             }
1029         }
1030         return ret;
1031     }
1032
1033     /**
1034      * Convert a container, list and choice subnodes (and recursivelly their
1035      * subnodes) of augment to generated types
1036      *
1037      * @param augBasePackageName
1038      *            string with the augment package name
1039      * @param augChildNodes
1040      *            set of data schema nodes which represents child nodes of the
1041      *            augment
1042      *
1043      * @return list of <code>Type</code> which represents container, list and
1044      *         choice subnodes of augment
1045      */
1046     private List<Type> augmentationBodyToGenTypes(final String augBasePackageName,
1047             final Set<DataSchemaNode> augChildNodes) {
1048         final List<Type> genTypes = new ArrayList<>();
1049         final List<DataNodeIterator> augSchemaIts = new ArrayList<>();
1050         for (final DataSchemaNode childNode : augChildNodes) {
1051             if (childNode instanceof DataNodeContainer) {
1052                 augSchemaIts.add(new DataNodeIterator((DataNodeContainer) childNode));
1053
1054                 if (childNode instanceof ContainerSchemaNode) {
1055                     genTypes.add(containerToGenType(augBasePackageName, (ContainerSchemaNode) childNode));
1056                 } else if (childNode instanceof ListSchemaNode) {
1057                     genTypes.addAll(listToGenType(augBasePackageName, (ListSchemaNode) childNode));
1058                 }
1059             } else if (childNode instanceof ChoiceNode) {
1060                 final ChoiceNode choice = (ChoiceNode) childNode;
1061                 for (final ChoiceCaseNode caseNode : choice.getCases()) {
1062                     augSchemaIts.add(new DataNodeIterator(caseNode));
1063                 }
1064                 genTypes.addAll(choiceToGeneratedType(augBasePackageName, (ChoiceNode) childNode));
1065             }
1066         }
1067
1068         for (final DataNodeIterator it : augSchemaIts) {
1069             final List<ContainerSchemaNode> augContainers = it.allContainers();
1070             final List<ListSchemaNode> augLists = it.allLists();
1071             final List<ChoiceNode> augChoices = it.allChoices();
1072
1073             if (augContainers != null) {
1074                 for (final ContainerSchemaNode container : augContainers) {
1075                     genTypes.add(containerToGenType(augBasePackageName, container));
1076                 }
1077             }
1078             if (augLists != null) {
1079                 for (final ListSchemaNode list : augLists) {
1080                     genTypes.addAll(listToGenType(augBasePackageName, list));
1081                 }
1082             }
1083             if (augChoices != null) {
1084                 for (final ChoiceNode choice : augChoices) {
1085                     genTypes.addAll(choiceToGeneratedType(augBasePackageName, choice));
1086                 }
1087             }
1088         }
1089         return genTypes;
1090     }
1091
1092     /**
1093      * Returns first unique name for the augment generated type builder. The
1094      * generated type builder name for augment consists from name of augmented
1095      * node and serial number of its augmentation.
1096      *
1097      * @param builders
1098      *            map of builders which were created in the package to which the
1099      *            augmentation belongs
1100      * @param genTypeName
1101      *            string with name of augmented node
1102      * @return string with unique name for augmentation builder
1103      */
1104     private String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
1105         String augTypeName = genTypeName;
1106
1107         int index = 1;
1108         while ((builders != null) && builders.containsKey(genTypeName + index)) {
1109             index++;
1110         }
1111         augTypeName += index;
1112         return augTypeName;
1113     }
1114
1115     /**
1116      * Converts <code>containerNode</code> to generated type. Firstly the
1117      * generated type builder is created. The subnodes of
1118      * <code>containerNode</code> are added as methods and the instance of
1119      * <code>GeneratedType</code> is returned.
1120      *
1121      * @param basePackageName
1122      *            string contains the module package name
1123      * @param containerNode
1124      *            container schema node with the data about childs nodes and
1125      *            schema paths
1126      * @return generated type for <code>containerNode</code>
1127      */
1128     private GeneratedType containerToGenType(final String basePackageName, ContainerSchemaNode containerNode) {
1129         if (containerNode == null) {
1130             return null;
1131         }
1132
1133         final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
1134         final Set<DataSchemaNode> schemaNodes = containerNode.getChildNodes();
1135         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, containerNode);
1136
1137         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
1138         return typeBuilder.toInstance();
1139     }
1140
1141     /**
1142      * Adds the methods to <code>typeBuilder</code> which represent subnodes of
1143      * node for which <code>typeBuilder</code> was created.
1144      *
1145      * The subnodes aren't mapped to the methods if they are part of grouping or
1146      * augment (in this case are already part of them).
1147      *
1148      * @param basePackageName
1149      *            string contains the module package name
1150      * @param typeBuilder
1151      *            generated type builder which represents any node. The subnodes
1152      *            of this node are added to the <code>typeBuilder</code> as
1153      *            methods. The subnode can be of type leaf, leaf-list, list,
1154      *            container, choice.
1155      * @param schemaNodes
1156      *            set of data schema nodes which are the children of the node
1157      *            for which <code>typeBuilder</code> was created
1158      * @return generated type builder which is the same builder as input
1159      *         parameter. The getter methods (representing child nodes) could be
1160      *         added to it.
1161      */
1162     private GeneratedTypeBuilder resolveDataSchemaNodes(final String basePackageName,
1163             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
1164         if ((schemaNodes != null) && (typeBuilder != null)) {
1165             for (final DataSchemaNode schemaNode : schemaNodes) {
1166                 if (schemaNode.isAugmenting() || schemaNode.isAddedByUses()) {
1167                     continue;
1168                 }
1169                 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
1170             }
1171         }
1172         return typeBuilder;
1173     }
1174
1175     /**
1176      * Adds the methods to <code>typeBuilder</code> what represents subnodes of
1177      * node for which <code>typeBuilder</code> was created.
1178      *
1179      * @param basePackageName
1180      *            string contains the module package name
1181      * @param typeBuilder
1182      *            generated type builder which represents any node. The subnodes
1183      *            of this node are added to the <code>typeBuilder</code> as
1184      *            methods. The subnode can be of type leaf, leaf-list, list,
1185      *            container, choice.
1186      * @param schemaNodes
1187      *            set of data schema nodes which are the children of the node
1188      *            for which <code>typeBuilder</code> was created
1189      * @return generated type builder which is the same object as the input
1190      *         parameter <code>typeBuilder</code>. The getter method could be
1191      *         added to it.
1192      */
1193     private GeneratedTypeBuilder augSchemaNodeToMethods(final String basePackageName,
1194             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
1195         if ((schemaNodes != null) && (typeBuilder != null)) {
1196             for (final DataSchemaNode schemaNode : schemaNodes) {
1197                 if (schemaNode.isAugmenting()) {
1198                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
1199                 }
1200             }
1201         }
1202         return typeBuilder;
1203     }
1204
1205     /**
1206      * Adds to <code>typeBuilder</code> a method which is derived from
1207      * <code>schemaNode</code>.
1208      *
1209      * @param basePackageName
1210      *            string with the module package name
1211      * @param schemaNode
1212      *            data schema node which is added to <code>typeBuilder</code> as
1213      *            a method
1214      * @param typeBuilder
1215      *            generated type builder to which is <code>schemaNode</code>
1216      *            added as a method.
1217      */
1218     private void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode schemaNode,
1219             final GeneratedTypeBuilder typeBuilder) {
1220         if (schemaNode != null && typeBuilder != null) {
1221             if (schemaNode instanceof LeafSchemaNode) {
1222                 resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) schemaNode);
1223             } else if (schemaNode instanceof LeafListSchemaNode) {
1224                 resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
1225             } else if (schemaNode instanceof ContainerSchemaNode) {
1226                 resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
1227             } else if (schemaNode instanceof ListSchemaNode) {
1228                 resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
1229             } else if (schemaNode instanceof ChoiceNode) {
1230                 resolveChoiceSchemaNode(basePackageName, typeBuilder, (ChoiceNode) schemaNode);
1231             }
1232         }
1233     }
1234
1235     /**
1236      * Creates a getter method for a choice node.
1237      *
1238      * Firstly generated type builder for choice is created or found in
1239      * {@link BindingGeneratorImpl#allGroupings allGroupings}. The package name
1240      * in the builder is created as concatenation of module package name and
1241      * names of all parent nodes. In the end the getter method for choice is
1242      * added to <code>typeBuilder</code> and return type is set to choice
1243      * builder.
1244      *
1245      * @param basePackageName
1246      *            string with the module package name
1247      * @param typeBuilder
1248      *            generated type builder to which is <code>choiceNode</code>
1249      *            added as getter method
1250      * @param choiceNode
1251      *            choice node which is mapped as a getter method
1252      * @throws IllegalArgumentException
1253      *             <ul>
1254      *             <li>if <code>basePackageName</code> equals null</li>
1255      *             <li>if <code>typeBuilder</code> equals null</li>
1256      *             <li>if <code>choiceNode</code> equals null</li>
1257      *             </ul>
1258      *
1259      */
1260     private void resolveChoiceSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
1261             final ChoiceNode choiceNode) {
1262         if (basePackageName == null) {
1263             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
1264         }
1265         if (typeBuilder == null) {
1266             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1267         }
1268         if (choiceNode == null) {
1269             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
1270         }
1271
1272         final String choiceName = choiceNode.getQName().getLocalName();
1273         if (choiceName != null && !choiceNode.isAddedByUses()) {
1274             final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
1275             final GeneratedTypeBuilder choiceType = addDefaultInterfaceDefinition(packageName, choiceNode);
1276             constructGetter(typeBuilder, choiceName, choiceNode.getDescription(), choiceType);
1277         }
1278     }
1279
1280     /**
1281      * Converts <code>choiceNode</code> to the list of generated types for
1282      * choice and its cases.
1283      *
1284      * The package names for choice and for its cases are created as
1285      * concatenation of the module package (<code>basePackageName</code>) and
1286      * names of all parents node.
1287      *
1288      * @param basePackageName
1289      *            string with the module package name
1290      * @param choiceNode
1291      *            choice node which is mapped to generated type. Also child
1292      *            nodes - cases are mapped to generated types.
1293      * @return list of generated types which contains generated type for choice
1294      *         and generated types for all cases which aren't added do choice
1295      *         through <i>uses</i>.
1296      * @throws IllegalArgumentException
1297      *             <ul>
1298      *             <li>if <code>basePackageName</code> equals null</li>
1299      *             <li>if <code>choiceNode</code> equals null</li>
1300      *             </ul>
1301      *
1302      */
1303     private List<GeneratedType> choiceToGeneratedType(final String basePackageName, final ChoiceNode choiceNode) {
1304         if (basePackageName == null) {
1305             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
1306         }
1307         if (choiceNode == null) {
1308             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
1309         }
1310
1311         final List<GeneratedType> generatedTypes = new ArrayList<>();
1312         final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
1313         final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
1314         choiceTypeBuilder.addImplementsType(Types.DATA_OBJECT);
1315         final GeneratedType choiceType = choiceTypeBuilder.toInstance();
1316
1317         generatedTypes.add(choiceType);
1318         final Set<ChoiceCaseNode> caseNodes = choiceNode.getCases();
1319         if ((caseNodes != null) && !caseNodes.isEmpty()) {
1320             generatedTypes.addAll(generateTypesFromChoiceCases(basePackageName, choiceType, caseNodes));
1321         }
1322         return generatedTypes;
1323     }
1324
1325     /**
1326      * Converts <code>caseNodes</code> set to list of corresponding generated
1327      * types.
1328      *
1329      * For every <i>case</i> which isn't added through augment or <i>uses</i> is
1330      * created generated type builder. The package names for the builder is
1331      * created as concatenation of the module package (
1332      * <code>basePackageName</code>) and names of all parents nodes of the
1333      * concrete <i>case</i>. There is also relation "<i>implements type</i>"
1334      * between every case builder and <i>choice</i> type
1335      *
1336      * @param basePackageName
1337      *            string with the module package name
1338      * @param refChoiceType
1339      *            type which represents superior <i>case</i>
1340      * @param caseNodes
1341      *            set of choice case nodes which are mapped to generated types
1342      * @return list of generated types for <code>caseNodes</code>.
1343      * @throws IllegalArgumentException
1344      *             <ul>
1345      *             <li>if <code>basePackageName</code> equals null</li>
1346      *             <li>if <code>refChoiceType</code> equals null</li>
1347      *             <li>if <code>caseNodes</code> equals null</li>
1348      *             </ul>
1349      *             *
1350      */
1351     private List<GeneratedType> generateTypesFromChoiceCases(final String basePackageName, final Type refChoiceType,
1352             final Set<ChoiceCaseNode> caseNodes) {
1353         if (basePackageName == null) {
1354             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
1355         }
1356         if (refChoiceType == null) {
1357             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
1358         }
1359         if (caseNodes == null) {
1360             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
1361         }
1362
1363         final List<GeneratedType> generatedTypes = new ArrayList<>();
1364         for (final ChoiceCaseNode caseNode : caseNodes) {
1365             if (caseNode != null && !caseNode.isAddedByUses() && !caseNode.isAugmenting()) {
1366                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
1367                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1368                 caseTypeBuilder.addImplementsType(refChoiceType);
1369
1370                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
1371                 if (childNodes != null) {
1372                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
1373                 }
1374                 generatedTypes.add(caseTypeBuilder.toInstance());
1375             }
1376         }
1377
1378         return generatedTypes;
1379     }
1380
1381     /**
1382      * Generates list of generated types for all the cases of a choice which are
1383      * added to the choice through the augment.
1384      *
1385      *
1386      * @param basePackageName
1387      *            string contains name of package to which augment belongs. If
1388      *            an augmented choice is from an other package (pcg1) than an
1389      *            augmenting choice (pcg2) then case's of the augmenting choice
1390      *            will belong to pcg2.
1391      * @param refChoiceType
1392      *            Type which represents the choice to which case belongs. Every
1393      *            case has to contain its choice in extend part.
1394      * @param caseNodes
1395      *            set of choice case nodes for which is checked if are/aren't
1396      *            added to choice through augmentation
1397      * @return list of generated types which represents augmented cases of
1398      *         choice <code>refChoiceType</code>
1399      * @throws IllegalArgumentException
1400      *             <ul>
1401      *             <li>if <code>basePackageName</code> equals null</li>
1402      *             <li>if <code>refChoiceType</code> equals null</li>
1403      *             <li>if <code>caseNodes</code> equals null</li>
1404      *             </ul>
1405      */
1406     private List<GeneratedType> generateTypesFromAugmentedChoiceCases(final String basePackageName,
1407             final Type refChoiceType, final Set<ChoiceCaseNode> caseNodes) {
1408         if (basePackageName == null) {
1409             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
1410         }
1411         if (refChoiceType == null) {
1412             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
1413         }
1414         if (caseNodes == null) {
1415             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
1416         }
1417
1418         final List<GeneratedType> generatedTypes = new ArrayList<>();
1419         for (final ChoiceCaseNode caseNode : caseNodes) {
1420             if (caseNode != null && caseNode.isAugmenting()) {
1421                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
1422                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
1423                 caseTypeBuilder.addImplementsType(refChoiceType);
1424
1425                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
1426                 if (childNodes != null) {
1427                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
1428                 }
1429                 generatedTypes.add(caseTypeBuilder.toInstance());
1430             }
1431         }
1432
1433         return generatedTypes;
1434     }
1435
1436     /**
1437      * Converts <code>leaf</code> to the getter method which is added to
1438      * <code>typeBuilder</code>.
1439      *
1440      * @param typeBuilder
1441      *            generated type builder to which is added getter method as
1442      *            <code>leaf</code> mapping
1443      * @param leaf
1444      *            leaf schema node which is mapped as getter method which is
1445      *            added to <code>typeBuilder</code>
1446      * @return boolean value
1447      *         <ul>
1448      *         <li>false - if <code>leaf</code> or <code>typeBuilder</code> are
1449      *         null</li>
1450      *         <li>true - in other cases</li>
1451      *         </ul>
1452      */
1453     private boolean resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
1454         if ((leaf != null) && (typeBuilder != null)) {
1455             final String leafName = leaf.getQName().getLocalName();
1456             String leafDesc = leaf.getDescription();
1457             if (leafDesc == null) {
1458                 leafDesc = "";
1459             }
1460
1461             final Module parentModule = findParentModule(schemaContext, leaf);
1462             if (leafName != null && !leaf.isAddedByUses()) {
1463                 final TypeDefinition<?> typeDef = leaf.getType();
1464
1465                 Type returnType = null;
1466                 if (typeDef instanceof EnumTypeDefinition) {
1467                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
1468                     final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
1469                     final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName,
1470                             typeBuilder);
1471
1472                     if (enumBuilder != null) {
1473                         returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
1474                     }
1475                     ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
1476                 } else if (typeDef instanceof UnionType) {
1477                     GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, parentModule);
1478                     if (genTOBuilder != null) {
1479                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
1480                     }
1481                 } else if (typeDef instanceof BitsTypeDefinition) {
1482                     GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, leafName, parentModule);
1483                     if (genTOBuilder != null) {
1484                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
1485                     }
1486                 } else {
1487                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
1488                 }
1489                 if (returnType != null) {
1490                     constructGetter(typeBuilder, leafName, leafDesc, returnType);
1491                     return true;
1492                 }
1493             }
1494         }
1495         return false;
1496     }
1497
1498     /**
1499      * Converts <code>leaf</code> schema node to property of generated TO
1500      * builder.
1501      *
1502      * @param toBuilder
1503      *            generated TO builder to which is <code>leaf</code> added as
1504      *            property
1505      * @param leaf
1506      *            leaf schema node which is added to <code>toBuilder</code> as
1507      *            property
1508      * @param isReadOnly
1509      *            boolean value which says if leaf property is|isn't read only
1510      * @return boolean value
1511      *         <ul>
1512      *         <li>false - if <code>leaf</code>, <code>toBuilder</code> or leaf
1513      *         name equals null or if leaf is added by <i>uses</i>.</li>
1514      *         <li>true - other cases</li>
1515      *         </ul>
1516      */
1517     private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
1518             boolean isReadOnly) {
1519         if ((leaf != null) && (toBuilder != null)) {
1520             final String leafName = leaf.getQName().getLocalName();
1521             String leafDesc = leaf.getDescription();
1522             if (leafDesc == null) {
1523                 leafDesc = "";
1524             }
1525
1526             if (leafName != null && !leaf.isAddedByUses()) {
1527                 final TypeDefinition<?> typeDef = leaf.getType();
1528
1529                 // TODO: properly resolve enum types
1530                 final Type returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
1531
1532                 if (returnType != null) {
1533                     final GeneratedPropertyBuilder propBuilder = toBuilder.addProperty(parseToClassName(leafName));
1534
1535                     propBuilder.setReadOnly(isReadOnly);
1536                     propBuilder.setReturnType(returnType);
1537                     propBuilder.setComment(leafDesc);
1538
1539                     toBuilder.addEqualsIdentity(propBuilder);
1540                     toBuilder.addHashIdentity(propBuilder);
1541                     toBuilder.addToStringProperty(propBuilder);
1542
1543                     return true;
1544                 }
1545             }
1546         }
1547         return false;
1548     }
1549
1550     /**
1551      * Converts <code>node</code> leaf list schema node to getter method of
1552      * <code>typeBuilder</code>.
1553      *
1554      * @param typeBuilder
1555      *            generated type builder to which is <code>node</code> added as
1556      *            getter method
1557      * @param node
1558      *            leaf list schema node which is added to
1559      *            <code>typeBuilder</code> as getter method
1560      * @return boolean value
1561      *         <ul>
1562      *         <li>true - if <code>node</code>, <code>typeBuilder</code>,
1563      *         nodeName equal null or <code>node</code> is added by <i>uses</i></li>
1564      *         <li>false - other cases</li>
1565      *         </ul>
1566      */
1567     private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node) {
1568         if ((node != null) && (typeBuilder != null)) {
1569             final String nodeName = node.getQName().getLocalName();
1570             String nodeDesc = node.getDescription();
1571             if (nodeDesc == null) {
1572                 nodeDesc = "";
1573             }
1574
1575             if (nodeName != null && !node.isAddedByUses()) {
1576                 final TypeDefinition<?> type = node.getType();
1577                 final Type listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type));
1578
1579                 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
1580                 return true;
1581             }
1582         }
1583         return false;
1584     }
1585
1586     /**
1587      * Creates a getter method for a container node.
1588      *
1589      * Firstly generated type builder for container is created or found in
1590      * {@link BindingGeneratorImpl#allGroupings allGroupings}. The package name
1591      * in the builder is created as concatenation of module package name and
1592      * names of all parent nodes. In the end the getter method for container is
1593      * added to <code>typeBuilder</code> and return type is set to container
1594      * type builder.
1595      *
1596      * @param basePackageName
1597      *            string with the module package name
1598      * @param typeBuilder
1599      *            generated type builder to which is <code>containerNode</code>
1600      *            added as getter method
1601      * @param containerNode
1602      *            container schema node which is mapped as getter method to
1603      *            <code>typeBuilder</code>
1604      * @return boolean value
1605      *         <ul>
1606      *         <li>false - if <code>containerNode</code>,
1607      *         <code>typeBuilder</code>, container node name equal null or
1608      *         <code>containerNode</code> is added by uses</li>
1609      *         <li>true - other cases</li>
1610      *         </ul>
1611      */
1612     private boolean resolveContainerSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
1613             final ContainerSchemaNode containerNode) {
1614         if ((containerNode != null) && (typeBuilder != null)) {
1615             final String nodeName = containerNode.getQName().getLocalName();
1616
1617             if (nodeName != null && !containerNode.isAddedByUses()) {
1618                 final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
1619
1620                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, containerNode);
1621                 constructGetter(typeBuilder, nodeName, containerNode.getDescription(), rawGenType);
1622
1623                 return true;
1624             }
1625         }
1626         return false;
1627     }
1628
1629     /**
1630      * Creates a getter method for a list node.
1631      *
1632      * Firstly generated type builder for list is created or found in
1633      * {@link BindingGeneratorImpl#allGroupings allGroupings}. The package name
1634      * in the builder is created as concatenation of module package name and
1635      * names of all parent nodes. In the end the getter method for list is added
1636      * to <code>typeBuilder</code> and return type is set to list type builder.
1637      *
1638      * @param basePackageName
1639      *            string with the module package name
1640      * @param typeBuilder
1641      *            generated type builder to which is <code></code> added as
1642      *            getter method
1643      * @param listNode
1644      *            list schema node which is mapped as getter method to
1645      *            <code>typeBuilder</code>
1646      * @return boolean value
1647      *         <ul>
1648      *         <li>false - if <code>listNode</code>, <code>typeBuilder</code>,
1649      *         list node name equal null or <code>listNode</code> is added by
1650      *         uses</li>
1651      *         <li>true - other cases</li>
1652      *         </ul>
1653      */
1654     private boolean resolveListSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
1655             final ListSchemaNode listNode) {
1656         if ((listNode != null) && (typeBuilder != null)) {
1657             final String listName = listNode.getQName().getLocalName();
1658
1659             if (listName != null && !listNode.isAddedByUses()) {
1660                 final String packageName = packageNameForGeneratedType(basePackageName, listNode.getPath());
1661                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, listNode);
1662                 constructGetter(typeBuilder, listName, listNode.getDescription(), Types.listTypeFor(rawGenType));
1663                 return true;
1664             }
1665         }
1666         return false;
1667     }
1668
1669     /**
1670      * Instantiates generated type builder with <code>packageName</code> and
1671      * <code>schemaNode</code>.
1672      *
1673      * The new builder always implements
1674      * {@link org.opendaylight.yangtools.yang.binding.DataObject DataObject}.<br />
1675      * If <code>schemaNode</code> is instance of GroupingDefinition it also
1676      * implements {@link org.opendaylight.yangtools.yang.binding.Augmentable
1677      * Augmentable}.<br />
1678      * If <code>schemaNode</code> is instance of
1679      * {@link org.opendaylight.yangtools.yang.model.api.DataNodeContainer
1680      * DataNodeContainer} it can also implement nodes which are specified in
1681      * <i>uses</i>.
1682      *
1683      * @param packageName
1684      *            string with the name of the package to which
1685      *            <code>schemaNode</code> belongs.
1686      * @param schemaNode
1687      *            schema node for which is created generated type builder
1688      * @return generated type builder <code>schemaNode</code>
1689      */
1690     private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
1691         final GeneratedTypeBuilder builder = addRawInterfaceDefinition(packageName, schemaNode, "");
1692         builder.addImplementsType(Types.DATA_OBJECT);
1693         if (!(schemaNode instanceof GroupingDefinition)) {
1694             builder.addImplementsType(Types.augmentableTypeFor(builder));
1695         }
1696
1697         if (schemaNode instanceof DataNodeContainer) {
1698             addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, builder);
1699         }
1700
1701         return builder;
1702     }
1703
1704     /**
1705      * Wraps the calling of the same overloaded method.
1706      *
1707      * @param packageName
1708      *            string with the package name to which returning generated type
1709      *            builder belongs
1710      * @param schemaNode
1711      *            schema node which provide data about the schema node name
1712      * @return generated type builder for <code>schemaNode</code>
1713      */
1714     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
1715         return addRawInterfaceDefinition(packageName, schemaNode, "");
1716     }
1717
1718     /**
1719      * Returns reference to generated type builder for specified
1720      * <code>schemaNode</code> with <code>packageName</code>.
1721      *
1722      * Firstly the generated type builder is searched in
1723      * {@link BindingGeneratorImpl#genTypeBuilders genTypeBuilders}. If it isn't
1724      * found it is created and added to <code>genTypeBuilders</code>.
1725      *
1726      * @param packageName
1727      *            string with the package name to which returning generated type
1728      *            builder belongs
1729      * @param schemaNode
1730      *            schema node which provide data about the schema node name
1731      * @return generated type builder for <code>schemaNode</code>
1732      * @throws IllegalArgumentException
1733      *             <ul>
1734      *             <li>if <code>schemaNode</code> equals null</li>
1735      *             <li>if <code>packageName</code> equals null</li>
1736      *             <li>if Q name of schema node is null</li>
1737      *             <li>if schema node name is nul</li>
1738      *             </ul>
1739      *
1740      */
1741     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
1742             final String prefix) {
1743         if (schemaNode == null) {
1744             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
1745         }
1746         if (packageName == null) {
1747             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1748         }
1749         if (schemaNode.getQName() == null) {
1750             throw new IllegalArgumentException("QName for Data Schema Node cannot be NULL!");
1751         }
1752         final String schemaNodeName = schemaNode.getQName().getLocalName();
1753         if (schemaNodeName == null) {
1754             throw new IllegalArgumentException("Local Name of QName for Data Schema Node cannot be NULL!");
1755         }
1756
1757         final String genTypeName;
1758         if (prefix == null) {
1759             genTypeName = parseToClassName(schemaNodeName);
1760         } else {
1761             genTypeName = prefix + parseToClassName(schemaNodeName);
1762         }
1763
1764         final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1765         if (!genTypeBuilders.containsKey(packageName)) {
1766             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
1767             builders.put(genTypeName, newType);
1768             genTypeBuilders.put(packageName, builders);
1769         } else {
1770             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1771             if (!builders.containsKey(genTypeName)) {
1772                 builders.put(genTypeName, newType);
1773             }
1774         }
1775         return newType;
1776     }
1777
1778     /**
1779      * Creates the name of the getter method from <code>methodName</code>.
1780      *
1781      * @param methodName
1782      *            string with the name of the getter method
1783      * @return string with the name of the getter method for
1784      *         <code>methodName</code> in JAVA method format
1785      */
1786     private String getterMethodName(final String methodName) {
1787         final StringBuilder method = new StringBuilder();
1788         method.append("get");
1789         method.append(parseToClassName(methodName));
1790         return method.toString();
1791     }
1792
1793     /**
1794      * Creates the name of the setter method from <code>methodName</code>.
1795      *
1796      * @param methodName
1797      *            string with the name of the setter method
1798      * @return string with the name of the setter method for
1799      *         <code>methodName</code> in JAVA method format
1800      */
1801     private String setterMethodName(final String methodName) {
1802         final StringBuilder method = new StringBuilder();
1803         method.append("set");
1804         method.append(parseToClassName(methodName));
1805         return method.toString();
1806     }
1807
1808     /**
1809      * Created a method signature builder as part of
1810      * <code>interfaceBuilder</code>.
1811      *
1812      * The method signature builder is created for the getter method of
1813      * <code>schemaNodeName</code>. Also <code>comment</code> and
1814      * <code>returnType</code> information are added to the builder.
1815      *
1816      * @param interfaceBuilder
1817      *            generated type builder for which the getter method should be
1818      *            created
1819      * @param schemaNodeName
1820      *            string with schema node name. The name will be the part of the
1821      *            getter method name.
1822      * @param comment
1823      *            string with comment for the getter method
1824      * @param returnType
1825      *            type which represents the return type of the getter method
1826      * @return method signature builder which represents the getter method of
1827      *         <code>interfaceBuilder</code>
1828      */
1829     private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
1830             final String schemaNodeName, final String comment, final Type returnType) {
1831         final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName));
1832
1833         getMethod.setComment(comment);
1834         getMethod.setReturnType(returnType);
1835
1836         return getMethod;
1837     }
1838
1839     /**
1840      * Creates a method signature builder as a part of
1841      * <code>interfaceBuilder</code> for <code>schemaNodeName</code>
1842      *
1843      * The method signature builder is created for the setter method of
1844      * <code>schemaNodeName</code>. Also <code>comment</code>
1845      * <code>parameterType</code> data are added to the builder. The return type
1846      * of the method is set to <code>void</code>.
1847      *
1848      * @param interfaceBuilder
1849      *            generated type builder for which the setter method should be
1850      *            created
1851      * @param schemaNodeName
1852      *            string with schema node name. The name will be the part of the
1853      *            setter method name.
1854      * @param comment
1855      *            string with comment for the setter method
1856      * @param parameterType
1857      *            type which represents the type of the setter method input
1858      *            parameter
1859      * @return method signature builder which represents the setter method of
1860      *         <code>interfaceBuilder</code>
1861      */
1862     private MethodSignatureBuilder constructSetter(final GeneratedTypeBuilder interfaceBuilder,
1863             final String schemaNodeName, final String comment, final Type parameterType) {
1864         final MethodSignatureBuilder setMethod = interfaceBuilder.addMethod(setterMethodName(schemaNodeName));
1865
1866         setMethod.setComment(comment);
1867         setMethod.addParameter(parameterType, parseToValidParamName(schemaNodeName));
1868         setMethod.setReturnType(Types.voidType());
1869
1870         return setMethod;
1871     }
1872
1873     private List<Type> listToGenType(final String basePackageName, final ListSchemaNode list) {
1874         if (basePackageName == null) {
1875             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1876         }
1877         if (list == null) {
1878             throw new IllegalArgumentException("List Schema Node cannot be NULL!");
1879         }
1880
1881         final String packageName = packageNameForGeneratedType(basePackageName, list.getPath());
1882         // final GeneratedTypeBuilder typeBuilder =
1883         // resolveListTypeBuilder(packageName, list);
1884         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, list);
1885
1886         final List<String> listKeys = listKeys(list);
1887         GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, list);
1888
1889         if (genTOBuilder != null) {
1890             ParameterizedType identifierMarker = Types.parameterizedTypeFor(Types.typeForClass(Identifier.class),
1891                     typeBuilder);
1892             ParameterizedType identifiableMarker = Types.parameterizedTypeFor(Types.typeForClass(Identifiable.class),
1893                     genTOBuilder);
1894             genTOBuilder.addImplementsType(identifierMarker);
1895             typeBuilder.addImplementsType(identifiableMarker);
1896         }
1897         final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
1898
1899         for (final DataSchemaNode schemaNode : schemaNodes) {
1900             if (schemaNode.isAugmenting()) {
1901                 continue;
1902             }
1903             addSchemaNodeToListBuilders(basePackageName, schemaNode, typeBuilder, genTOBuilder, listKeys);
1904         }
1905         return typeBuildersToGenTypes(typeBuilder, genTOBuilder);
1906     }
1907
1908     /**
1909      * Adds <code>schemaNode</code> to <code>typeBuilder</code> as getter method
1910      * or to <code>genTOBuilder</code> as property.
1911      *
1912      * @param basePackageName
1913      *            string contains the module package name
1914      * @param schemaNode
1915      *            data schema node which should be added as getter method to
1916      *            <code>typeBuilder</code> or as a property to
1917      *            <code>genTOBuilder</code> if is part of the list key
1918      * @param typeBuilder
1919      *            generated type builder for the list schema node
1920      * @param genTOBuilder
1921      *            generated TO builder for the list keys
1922      * @param listKeys
1923      *            list of string which contains names of the list keys
1924      * @throws IllegalArgumentException
1925      *             <ul>
1926      *             <li>if <code>schemaNode</code> equals null</li>
1927      *             <li>if <code>typeBuilder</code> equals null</li>
1928      *             </ul>
1929      */
1930     private void addSchemaNodeToListBuilders(final String basePackageName, final DataSchemaNode schemaNode,
1931             final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys) {
1932         if (schemaNode == null) {
1933             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
1934         }
1935
1936         if (typeBuilder == null) {
1937             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1938         }
1939
1940         if (schemaNode instanceof LeafSchemaNode) {
1941             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1942             final String leafName = leaf.getQName().getLocalName();
1943             if (!listKeys.contains(leafName)) {
1944                 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1945             } else {
1946                 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1947             }
1948         } else if (schemaNode instanceof LeafListSchemaNode) {
1949             resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
1950         } else if (schemaNode instanceof ContainerSchemaNode) {
1951             resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
1952         } else if (schemaNode instanceof ListSchemaNode) {
1953             resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
1954         }
1955     }
1956
1957     private List<Type> typeBuildersToGenTypes(final GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1958         final List<Type> genTypes = new ArrayList<>();
1959         if (typeBuilder == null) {
1960             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1961         }
1962
1963         if (genTOBuilder != null) {
1964             final GeneratedTransferObject genTO = genTOBuilder.toInstance();
1965             constructGetter(typeBuilder, "key", "Returns Primary Key of Yang List Type", genTO);
1966             genTypes.add(genTO);
1967         }
1968         genTypes.add(typeBuilder.toInstance());
1969         return genTypes;
1970     }
1971
1972     /**
1973      * Selects the names of the list keys from <code>list</code> and returns
1974      * them as the list of the strings
1975      *
1976      * @param list
1977      *            of string with names of the list keys
1978      * @return list of string which represents names of the list keys. If the
1979      *         <code>list</code> contains no keys then the empty list is
1980      *         returned.
1981      */
1982     private List<String> listKeys(final ListSchemaNode list) {
1983         final List<String> listKeys = new ArrayList<>();
1984
1985         if (list.getKeyDefinition() != null) {
1986             final List<QName> keyDefinitions = list.getKeyDefinition();
1987
1988             for (final QName keyDefinition : keyDefinitions) {
1989                 listKeys.add(keyDefinition.getLocalName());
1990             }
1991         }
1992         return listKeys;
1993     }
1994
1995     /**
1996      * Generates for the <code>list</code> which contains any list keys special
1997      * generated TO builder.
1998      *
1999      * @param packageName
2000      *            string with package name to which the list belongs
2001      * @param list
2002      *            list schema node which is source of data about the list name
2003      * @return generated TO builder which represents the keys of the
2004      *         <code>list</code> or null if <code>list</code> is null or list of
2005      *         key definitions is null or empty.
2006      */
2007     private GeneratedTOBuilder resolveListKeyTOBuilder(final String packageName, final ListSchemaNode list) {
2008         GeneratedTOBuilder genTOBuilder = null;
2009         if ((list.getKeyDefinition() != null) && (!list.getKeyDefinition().isEmpty())) {
2010             if (list != null) {
2011                 final String listName = list.getQName().getLocalName() + "Key";
2012                 genTOBuilder = schemaNodeToTransferObjectBuilder(packageName, listName);
2013             }
2014         }
2015         return genTOBuilder;
2016
2017     }
2018
2019     /**
2020      * Builds generated TO builders for <code>typeDef</code> of type
2021      * {@link org.opendaylight.yangtools.yang.model.util.UnionType UnionType} or
2022      * {@link org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
2023      * BitsTypeDefinition} which are also added to <code>typeBuilder</code> as
2024      * enclosing transfer object.
2025      *
2026      * @param typeDef
2027      *            type definition which can be of type <code>UnionType</code> or
2028      *            <code>BitsTypeDefinition</code>
2029      * @param typeBuilder
2030      *            generated type builder to which is added generated TO created
2031      *            from <code>typeDef</code>
2032      * @param leafName
2033      *            string with name for generated TO builder
2034      * @return generated TO builder for <code>typeDef</code>
2035      */
2036     private GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
2037             String leafName, Module parentModule) {
2038         final String classNameFromLeaf = parseToClassName(leafName);
2039         GeneratedTOBuilder genTOBuilder = null;
2040         final String packageName = typeBuilder.getFullyQualifiedName();
2041         if (typeDef instanceof UnionTypeDefinition) {
2042             genTOBuilder = ((TypeProviderImpl) typeProvider).provideGeneratedTOBuilderForUnionTypeDefinition(
2043                     packageName, typeDef, classNameFromLeaf, parentModule);
2044         } else if (typeDef instanceof BitsTypeDefinition) {
2045             genTOBuilder = ((TypeProviderImpl) typeProvider).provideGeneratedTOBuilderForBitsTypeDefinition(
2046                     packageName, typeDef, classNameFromLeaf);
2047         }
2048         if (genTOBuilder != null) {
2049             typeBuilder.addEnclosingTransferObject(genTOBuilder);
2050             return genTOBuilder;
2051         }
2052         return null;
2053
2054     }
2055
2056     /**
2057      * Adds the implemented types to type builder.
2058      *
2059      * The method passes through the list of <i>uses</i> in
2060      * {@code dataNodeContainer}. For every <i>use</i> is obtained coresponding
2061      * generated type from {@link BindingGeneratorImpl#allGroupings
2062      * allGroupings} which is adde as <i>implements type</i> to
2063      * <code>builder</code>
2064      *
2065      * @param dataNodeContainer
2066      *            element which contains the list of used YANG groupings
2067      * @param builder
2068      *            builder to which are added implemented types according to
2069      *            <code>dataNodeContainer</code>
2070      * @return generated type builder with all implemented types
2071      */
2072     private GeneratedTypeBuilder addImplementedInterfaceFromUses(final DataNodeContainer dataNodeContainer,
2073             final GeneratedTypeBuilder builder) {
2074         for (UsesNode usesNode : dataNodeContainer.getUses()) {
2075             if (usesNode.getGroupingPath() != null) {
2076                 GeneratedType genType = allGroupings.get(usesNode.getGroupingPath());
2077                 if (genType == null) {
2078                     throw new IllegalStateException("Grouping " + usesNode.getGroupingPath() + "is not resolved for "
2079                             + builder.getName());
2080                 }
2081                 builder.addImplementsType(genType);
2082             }
2083         }
2084         return builder;
2085     }
2086
2087 }