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