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