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