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