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