bc767edd2d6ad4a85f489ebf1190a2bb1dac0af0
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-generator-impl / src / main / java / org / opendaylight / controller / 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.controller.sal.binding.generator.impl;
9
10 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.moduleNamespaceToPackageName;
11 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
12 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.parseToClassName;
13 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.parseToValidParamName;
14 import static org.opendaylight.controller.binding.generator.util.BindingGeneratorUtil.schemaNodeToTransferObjectBuilder;
15 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.findDataSchemaNode;
16 import static org.opendaylight.controller.yang.model.util.SchemaContextUtil.findParentModule;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.Comparator;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.concurrent.Future;
26
27 import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl;
28 import org.opendaylight.controller.binding.generator.util.Types;
29 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
30 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTypeBuilderImpl;
31 import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator;
32 import org.opendaylight.controller.sal.binding.generator.spi.TypeProvider;
33 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject;
34 import org.opendaylight.controller.sal.binding.model.api.GeneratedType;
35 import org.opendaylight.controller.sal.binding.model.api.Type;
36 import org.opendaylight.controller.sal.binding.model.api.type.builder.EnumBuilder;
37 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
38 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTOBuilder;
39 import org.opendaylight.controller.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
40 import org.opendaylight.controller.sal.binding.model.api.type.builder.MethodSignatureBuilder;
41 import org.opendaylight.controller.sal.binding.yang.types.GroupingDefinitionDependencySort;
42 import org.opendaylight.controller.sal.binding.yang.types.TypeProviderImpl;
43 import org.opendaylight.controller.yang.binding.Notification;
44 import org.opendaylight.controller.yang.common.QName;
45 import org.opendaylight.controller.yang.common.RpcResult;
46 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
47 import org.opendaylight.controller.yang.model.api.ChoiceCaseNode;
48 import org.opendaylight.controller.yang.model.api.ChoiceNode;
49 import org.opendaylight.controller.yang.model.api.ContainerSchemaNode;
50 import org.opendaylight.controller.yang.model.api.DataNodeContainer;
51 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
52 import org.opendaylight.controller.yang.model.api.GroupingDefinition;
53 import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
54 import org.opendaylight.controller.yang.model.api.LeafListSchemaNode;
55 import org.opendaylight.controller.yang.model.api.LeafSchemaNode;
56 import org.opendaylight.controller.yang.model.api.ListSchemaNode;
57 import org.opendaylight.controller.yang.model.api.Module;
58 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
59 import org.opendaylight.controller.yang.model.api.RpcDefinition;
60 import org.opendaylight.controller.yang.model.api.SchemaContext;
61 import org.opendaylight.controller.yang.model.api.SchemaNode;
62 import org.opendaylight.controller.yang.model.api.SchemaPath;
63 import org.opendaylight.controller.yang.model.api.TypeDefinition;
64 import org.opendaylight.controller.yang.model.api.UsesNode;
65 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
66 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
67 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
68 import org.opendaylight.controller.yang.model.util.DataNodeIterator;
69 import org.opendaylight.controller.yang.model.util.ExtendedType;
70 import org.opendaylight.controller.yang.model.util.SchemaContextUtil;
71 import org.opendaylight.controller.yang.model.util.UnionType;
72
73 public final class BindingGeneratorImpl implements BindingGenerator {
74
75     private Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders;
76     private TypeProvider typeProvider;
77     private SchemaContext schemaContext;
78     private final Map<SchemaPath, GeneratedType> allGroupings = new HashMap<SchemaPath, GeneratedType>();
79
80     public BindingGeneratorImpl() {
81         super();
82     }
83
84     @Override
85     public List<Type> generateTypes(final SchemaContext context) {
86         if (context == null) {
87             throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
88         }
89         if (context.getModules() == null) {
90             throw new IllegalStateException("Schema Context does not contain defined modules!");
91         }
92
93         final List<Type> generatedTypes = new ArrayList<>();
94         schemaContext = context;
95         typeProvider = new TypeProviderImpl(context);
96         final Set<Module> modules = context.getModules();
97         genTypeBuilders = new HashMap<>();
98         for (final Module module : modules) {
99             generatedTypes.addAll(allGroupingsToGenTypes(module));
100             generatedTypes.add(moduleToDataType(module));
101             generatedTypes.addAll(allTypeDefinitionsToGenTypes(module));
102             generatedTypes.addAll(allContainersToGenTypes(module));
103             generatedTypes.addAll(allListsToGenTypes(module));
104             generatedTypes.addAll(allChoicesToGenTypes(module));
105             generatedTypes.addAll(allAugmentsToGenTypes(module));
106             generatedTypes.addAll(allRPCMethodsToGenType(module));
107             generatedTypes.addAll(allNotificationsToGenType(module));
108             generatedTypes.addAll(allIdentitiesToGenTypes(module, context));
109
110         }
111         return generatedTypes;
112     }
113
114     @Override
115     public List<Type> generateTypes(final SchemaContext context, final Set<Module> modules) {
116         if (context == null) {
117             throw new IllegalArgumentException("Schema Context reference cannot be NULL!");
118         }
119         if (context.getModules() == null) {
120             throw new IllegalStateException("Schema Context does not contain defined modules!");
121         }
122         if (modules == null) {
123             throw new IllegalArgumentException("Sef of Modules cannot be NULL!");
124         }
125
126         final List<Type> filteredGenTypes = new ArrayList<>();
127         schemaContext = context;
128         typeProvider = new TypeProviderImpl(context);
129         final Set<Module> contextModules = context.getModules();
130         genTypeBuilders = new HashMap<>();
131         for (final Module contextModule : contextModules) {
132             final List<Type> generatedTypes = new ArrayList<>();
133
134             generatedTypes.addAll(allGroupingsToGenTypes(contextModule));
135             generatedTypes.add(moduleToDataType(contextModule));
136             generatedTypes.addAll(allTypeDefinitionsToGenTypes(contextModule));
137             generatedTypes.addAll(allContainersToGenTypes(contextModule));
138             generatedTypes.addAll(allListsToGenTypes(contextModule));
139             generatedTypes.addAll(allChoicesToGenTypes(contextModule));
140             generatedTypes.addAll(allAugmentsToGenTypes(contextModule));
141             generatedTypes.addAll(allRPCMethodsToGenType(contextModule));
142             generatedTypes.addAll(allNotificationsToGenType(contextModule));
143             generatedTypes.addAll(allIdentitiesToGenTypes(contextModule, context));
144
145             if (modules.contains(contextModule)) {
146                 filteredGenTypes.addAll(generatedTypes);
147             }
148         }
149         return filteredGenTypes;
150     }
151
152     private List<Type> allTypeDefinitionsToGenTypes(final Module module) {
153         if (module == null) {
154             throw new IllegalArgumentException("Module reference cannot be NULL!");
155         }
156         if (module.getName() == null) {
157             throw new IllegalArgumentException("Module name cannot be NULL!");
158         }
159         if (module.getTypeDefinitions() == null) {
160             throw new IllegalArgumentException("Type Definitions for module " + module.getName() + " cannot be NULL!");
161         }
162
163         final Set<TypeDefinition<?>> typeDefinitions = module.getTypeDefinitions();
164         final List<Type> generatedTypes = new ArrayList<>();
165         for (final TypeDefinition<?> typedef : typeDefinitions) {
166             if (typedef != null) {
167                 final Type type = ((TypeProviderImpl) typeProvider).generatedTypeForExtendedDefinitionType(typedef);
168                 if ((type != null) && !generatedTypes.contains(type)) {
169                     generatedTypes.add(type);
170                 }
171             }
172         }
173         return generatedTypes;
174     }
175
176     private List<Type> allContainersToGenTypes(final Module module) {
177         if (module == null) {
178             throw new IllegalArgumentException("Module reference cannot be NULL!");
179         }
180
181         if (module.getName() == null) {
182             throw new IllegalArgumentException("Module name cannot be NULL!");
183         }
184
185         if (module.getChildNodes() == null) {
186             throw new IllegalArgumentException("Reference to Set of Child Nodes in module " + module.getName()
187                     + " cannot be NULL!");
188         }
189
190         final List<Type> generatedTypes = new ArrayList<>();
191         final DataNodeIterator it = new DataNodeIterator(module);
192         final List<ContainerSchemaNode> schemaContainers = it.allContainers();
193         final String basePackageName = moduleNamespaceToPackageName(module);
194         for (final ContainerSchemaNode container : schemaContainers) {
195             if (!container.isAddedByUses()) {
196                 generatedTypes.add(containerToGenType(basePackageName, container));
197             }
198         }
199         return generatedTypes;
200     }
201
202     private List<Type> allListsToGenTypes(final Module module) {
203         if (module == null) {
204             throw new IllegalArgumentException("Module reference cannot be NULL!");
205         }
206
207         if (module.getName() == null) {
208             throw new IllegalArgumentException("Module name cannot be NULL!");
209         }
210
211         if (module.getChildNodes() == null) {
212             throw new IllegalArgumentException("Reference to Set of Child Nodes in module " + module.getName()
213                     + " cannot be NULL!");
214         }
215
216         final List<Type> generatedTypes = new ArrayList<>();
217         final DataNodeIterator it = new DataNodeIterator(module);
218         final List<ListSchemaNode> schemaLists = it.allLists();
219         final String basePackageName = moduleNamespaceToPackageName(module);
220         if (schemaLists != null) {
221             for (final ListSchemaNode list : schemaLists) {
222                 if (!list.isAddedByUses()) {
223                     generatedTypes.addAll(listToGenType(basePackageName, list));
224                 }
225             }
226         }
227         return generatedTypes;
228     }
229
230     private List<GeneratedType> allChoicesToGenTypes(final Module module) {
231         if (module == null) {
232             throw new IllegalArgumentException("Module reference cannot be NULL!");
233         }
234         if (module.getName() == null) {
235             throw new IllegalArgumentException("Module name cannot be NULL!");
236         }
237
238         final DataNodeIterator it = new DataNodeIterator(module);
239         final List<ChoiceNode> choiceNodes = it.allChoices();
240         final String basePackageName = moduleNamespaceToPackageName(module);
241
242         final List<GeneratedType> generatedTypes = new ArrayList<>();
243         for (final ChoiceNode choice : choiceNodes) {
244             if ((choice != null) && !choice.isAddedByUses()) {
245                 generatedTypes.addAll(choiceToGeneratedType(basePackageName, choice));
246             }
247         }
248         return generatedTypes;
249     }
250
251     private List<Type> allAugmentsToGenTypes(final Module module) {
252         if (module == null) {
253             throw new IllegalArgumentException("Module reference cannot be NULL!");
254         }
255         if (module.getName() == null) {
256             throw new IllegalArgumentException("Module name cannot be NULL!");
257         }
258         if (module.getChildNodes() == null) {
259             throw new IllegalArgumentException("Reference to Set of Augmentation Definitions in module "
260                     + module.getName() + " cannot be NULL!");
261         }
262
263         final List<Type> generatedTypes = new ArrayList<>();
264         final String basePackageName = moduleNamespaceToPackageName(module);
265         final List<AugmentationSchema> augmentations = resolveAugmentations(module);
266         for (final AugmentationSchema augment : augmentations) {
267             generatedTypes.addAll(augmentationToGenTypes(basePackageName, augment));
268         }
269         return generatedTypes;
270     }
271
272     private List<AugmentationSchema> resolveAugmentations(final Module module) {
273         if (module == null) {
274             throw new IllegalArgumentException("Module reference cannot be NULL!");
275         }
276         if (module.getAugmentations() == null) {
277             throw new IllegalStateException("Augmentations Set cannot be NULL!");
278         }
279
280         final Set<AugmentationSchema> augmentations = module.getAugmentations();
281         final List<AugmentationSchema> sortedAugmentations = new ArrayList<>(augmentations);
282         Collections.sort(sortedAugmentations, new Comparator<AugmentationSchema>() {
283
284             @Override
285             public int compare(AugmentationSchema augSchema1, AugmentationSchema augSchema2) {
286
287                 if (augSchema1.getTargetPath().getPath().size() > augSchema2.getTargetPath().getPath().size()) {
288                     return 1;
289                 } else if (augSchema1.getTargetPath().getPath().size() < augSchema2.getTargetPath().getPath().size()) {
290                     return -1;
291                 }
292                 return 0;
293
294             }
295         });
296
297         return sortedAugmentations;
298     }
299
300     private GeneratedType moduleToDataType(final Module module) {
301         if (module == null) {
302             throw new IllegalArgumentException("Module reference cannot be NULL!");
303         }
304
305         final GeneratedTypeBuilder moduleDataTypeBuilder = moduleTypeBuilder(module, "Data");
306         addInterfaceDefinition(module, moduleDataTypeBuilder);
307
308         final String basePackageName = moduleNamespaceToPackageName(module);
309         if (moduleDataTypeBuilder != null) {
310             final Set<DataSchemaNode> dataNodes = module.getChildNodes();
311             resolveDataSchemaNodes(basePackageName, moduleDataTypeBuilder, dataNodes);
312         }
313         return moduleDataTypeBuilder.toInstance();
314     }
315
316     private List<Type> allRPCMethodsToGenType(final Module module) {
317         if (module == null) {
318             throw new IllegalArgumentException("Module reference cannot be NULL!");
319         }
320
321         if (module.getName() == null) {
322             throw new IllegalArgumentException("Module name cannot be NULL!");
323         }
324
325         if (module.getChildNodes() == null) {
326             throw new IllegalArgumentException("Reference to Set of RPC Method Definitions in module "
327                     + module.getName() + " cannot be NULL!");
328         }
329
330         final String basePackageName = moduleNamespaceToPackageName(module);
331         final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
332         final List<Type> genRPCTypes = new ArrayList<>();
333         final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, "Service");
334         final Type future = Types.typeForClass(Future.class);
335         for (final RpcDefinition rpc : rpcDefinitions) {
336             if (rpc != null) {
337
338                 String rpcName = parseToClassName(rpc.getQName().getLocalName());
339                 String rpcMethodName = parseToValidParamName(rpcName);
340                 MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
341
342                 final List<DataNodeIterator> rpcInOut = new ArrayList<>();
343
344                 ContainerSchemaNode input = rpc.getInput();
345                 ContainerSchemaNode output = rpc.getOutput();
346
347                 if (input != null) {
348                     rpcInOut.add(new DataNodeIterator(input));
349                     GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
350                     addInterfaceDefinition(input, inType);
351                     resolveDataSchemaNodes(basePackageName, inType, input.getChildNodes());
352                     Type inTypeInstance = inType.toInstance();
353                     genRPCTypes.add(inTypeInstance);
354                     method.addParameter(inTypeInstance, "input");
355                 }
356
357                 Type outTypeInstance = Types.typeForClass(Void.class);
358                 if (output != null) {
359                     rpcInOut.add(new DataNodeIterator(output));
360                     GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
361                     addInterfaceDefinition(output, outType);
362                     resolveDataSchemaNodes(basePackageName, outType, output.getChildNodes());
363                     outTypeInstance = outType.toInstance();
364                     genRPCTypes.add(outTypeInstance);
365
366                 }
367
368                 final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
369                 method.setReturnType(Types.parameterizedTypeFor(future, rpcRes));
370                 for (DataNodeIterator it : rpcInOut) {
371                     List<ContainerSchemaNode> nContainers = it.allContainers();
372                     if ((nContainers != null) && !nContainers.isEmpty()) {
373                         for (final ContainerSchemaNode container : nContainers) {
374                             if (!container.isAddedByUses()) {
375                                 genRPCTypes.add(containerToGenType(basePackageName, container));
376                             }
377                         }
378                     }
379                     List<ListSchemaNode> nLists = it.allLists();
380                     if ((nLists != null) && !nLists.isEmpty()) {
381                         for (final ListSchemaNode list : nLists) {
382                             if (!list.isAddedByUses()) {
383                                 genRPCTypes.addAll(listToGenType(basePackageName, list));
384                             }
385                         }
386                     }
387                 }
388             }
389         }
390         genRPCTypes.add(interfaceBuilder.toInstance());
391         return genRPCTypes;
392     }
393
394     private List<Type> allNotificationsToGenType(final Module module) {
395         if (module == null) {
396             throw new IllegalArgumentException("Module reference cannot be NULL!");
397         }
398
399         if (module.getName() == null) {
400             throw new IllegalArgumentException("Module name cannot be NULL!");
401         }
402
403         if (module.getChildNodes() == null) {
404             throw new IllegalArgumentException("Reference to Set of Notification Definitions in module "
405                     + module.getName() + " cannot be NULL!");
406         }
407
408         final String basePackageName = moduleNamespaceToPackageName(module);
409         final List<Type> genNotifyTypes = new ArrayList<>();
410         final Set<NotificationDefinition> notifications = module.getNotifications();
411
412         for (final NotificationDefinition notification : notifications) {
413             if (notification != null) {
414                 DataNodeIterator it = new DataNodeIterator(notification);
415
416                 // Containers
417                 for (ContainerSchemaNode node : it.allContainers()) {
418                     if (!node.isAddedByUses()) {
419                         genNotifyTypes.add(containerToGenType(basePackageName, node));
420                     }
421                 }
422                 // Lists
423                 for (ListSchemaNode node : it.allLists()) {
424                     if (!node.isAddedByUses()) {
425                         genNotifyTypes.addAll(listToGenType(basePackageName, node));
426                     }
427                 }
428                 final GeneratedTypeBuilder notificationTypeBuilder = addDefaultInterfaceDefinition(basePackageName,
429                         notification);
430                 notificationTypeBuilder.addImplementsType(Types.typeForClass(Notification.class));
431                 // Notification object
432                 resolveDataSchemaNodes(basePackageName, notificationTypeBuilder, notification.getChildNodes());
433                 genNotifyTypes.add(notificationTypeBuilder.toInstance());
434             }
435         }
436         return genNotifyTypes;
437     }
438
439     private List<Type> allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
440         List<Type> genTypes = new ArrayList<>();
441
442         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
443
444         final String basePackageName = moduleNamespaceToPackageName(module);
445
446         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
447             for (final IdentitySchemaNode identity : schemaIdentities) {
448                 genTypes.add(identityToGenType(basePackageName, identity, context));
449             }
450         }
451         return genTypes;
452     }
453
454     private GeneratedType identityToGenType(final String basePackageName, final IdentitySchemaNode identity,
455             final SchemaContext context) {
456         if (identity == null) {
457             return null;
458         }
459
460         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
461         final String genTypeName = parseToClassName(identity.getQName().getLocalName());
462         final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
463
464         IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
465         if (baseIdentity != null) {
466             Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
467
468             final String returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
469             final String returnTypeName = parseToClassName(baseIdentity.getQName().getLocalName());
470
471             GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
472             newType.setExtendsType(gto);
473         } else {
474             newType.setExtendsType(Types.getBaseIdentityTO());
475         }
476         newType.setAbstract(true);
477         return newType.toInstance();
478     }
479
480     private List<Type> allGroupingsToGenTypes(final Module module) {
481         final List<Type> genTypes = new ArrayList<>();
482         final String basePackageName = moduleNamespaceToPackageName(module);
483         final Set<GroupingDefinition> groupings = module.getGroupings();
484         List<GroupingDefinition> groupingsSortedByDependencies;
485         // groupingsSortedByDependencies =
486         // sortGroupingDefinitionsByUses(groupings);
487         groupingsSortedByDependencies = GroupingDefinitionDependencySort.sort(groupings);
488
489         for (final GroupingDefinition grouping : groupingsSortedByDependencies) {
490             GeneratedType genType = groupingToGenType(basePackageName, grouping);
491             genTypes.add(genType);
492             SchemaPath schemaPath = grouping.getPath();
493             allGroupings.put(schemaPath, genType);
494         }
495         return genTypes;
496     }
497
498     private GeneratedType groupingToGenType(final String basePackageName, GroupingDefinition grouping) {
499         if (grouping == null) {
500             return null;
501         }
502
503         final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath());
504         final Set<DataSchemaNode> schemaNodes = grouping.getChildNodes();
505         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, grouping);
506
507         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
508         return typeBuilder.toInstance();
509     }
510
511     private EnumTypeDefinition enumTypeDefFromExtendedType(final TypeDefinition<?> typeDefinition) {
512         if (typeDefinition != null) {
513             if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
514                 return (EnumTypeDefinition) typeDefinition.getBaseType();
515             } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
516                 return enumTypeDefFromExtendedType(typeDefinition.getBaseType());
517             }
518         }
519         return null;
520     }
521
522     private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final String enumName,
523             final GeneratedTypeBuilder typeBuilder) {
524         if ((enumTypeDef != null) && (typeBuilder != null) && (enumTypeDef.getQName() != null)
525                 && (enumTypeDef.getQName().getLocalName() != null)) {
526
527             final String enumerationName = parseToClassName(enumName);
528             final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
529
530             if (enumBuilder != null) {
531                 final List<EnumPair> enums = enumTypeDef.getValues();
532                 if (enums != null) {
533                     int listIndex = 0;
534                     for (final EnumPair enumPair : enums) {
535                         if (enumPair != null) {
536                             final String enumPairName = parseToClassName(enumPair.getName());
537                             Integer enumPairValue = enumPair.getValue();
538
539                             if (enumPairValue == null) {
540                                 enumPairValue = listIndex;
541                             }
542                             enumBuilder.addValue(enumPairName, enumPairValue);
543                             listIndex++;
544                         }
545                     }
546                 }
547                 return enumBuilder;
548             }
549         }
550         return null;
551     }
552
553     private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
554         if (module == null) {
555             throw new IllegalArgumentException("Module reference cannot be NULL!");
556         }
557         String packageName = moduleNamespaceToPackageName(module);
558         final String moduleName = parseToClassName(module.getName()) + postfix;
559
560         return new GeneratedTypeBuilderImpl(packageName, moduleName);
561
562     }
563
564     private List<Type> augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema) {
565         if (augmentPackageName == null) {
566             throw new IllegalArgumentException("Package Name cannot be NULL!");
567         }
568         if (augSchema == null) {
569             throw new IllegalArgumentException("Augmentation Schema cannot be NULL!");
570         }
571         if (augSchema.getTargetPath() == null) {
572             throw new IllegalStateException("Augmentation Schema does not contain Target Path (Target Path is NULL).");
573         }
574
575         final List<Type> genTypes = new ArrayList<>();
576
577         // EVERY augmented interface will extends Augmentation<T> interface
578         // and DataObject interface!!!
579         final SchemaPath targetPath = augSchema.getTargetPath();
580         final DataSchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
581         if ((targetSchemaNode != null) && (targetSchemaNode.getQName() != null)
582                 && (targetSchemaNode.getQName().getLocalName() != null)) {
583             final Module targetModule = findParentModule(schemaContext, targetSchemaNode);
584             final String targetBasePackage = moduleNamespaceToPackageName(targetModule);
585             final String targetPackageName = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());
586             final String targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();
587             final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
588
589             if (!(targetSchemaNode instanceof ChoiceNode)) {
590                 final GeneratedTypeBuilder augTypeBuilder = addRawAugmentGenTypeDefinition(augmentPackageName,
591                         targetPackageName, targetSchemaNodeName, augSchema);
592                 addInterfaceDefinition(augSchema, augTypeBuilder);
593
594                 final GeneratedType augType = augTypeBuilder.toInstance();
595                 genTypes.add(augType);
596             } else {
597                 final Type refChoiceType = new ReferencedTypeImpl(targetPackageName,
598                         parseToClassName(targetSchemaNodeName));
599                 final ChoiceNode choiceTarget = (ChoiceNode) targetSchemaNode;
600                 final Set<ChoiceCaseNode> choiceCaseNodes = choiceTarget.getCases();
601                 genTypes.addAll(augmentCasesToGenTypes(augmentPackageName, refChoiceType, choiceCaseNodes));
602             }
603             genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes));
604         }
605         return genTypes;
606     }
607
608     private List<GeneratedType> augmentCasesToGenTypes(final String augmentPackageName, final Type refChoiceType,
609             final Set<ChoiceCaseNode> choiceCaseNodes) {
610         if (augmentPackageName == null) {
611             throw new IllegalArgumentException("Augment Package Name string cannot be NULL!");
612         }
613         if (choiceCaseNodes == null) {
614             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
615         }
616         final List<GeneratedType> genTypes = generateTypesFromAugmentedChoiceCases(augmentPackageName, refChoiceType,
617                 choiceCaseNodes);
618         return genTypes;
619     }
620
621     private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final String augmentPackageName,
622             final String targetPackageName, final String targetSchemaNodeName, final AugmentationSchema augSchema) {
623         final String targetTypeName = parseToClassName(targetSchemaNodeName);
624         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
625         if (augmentBuilders == null) {
626             augmentBuilders = new HashMap<>();
627             genTypeBuilders.put(augmentPackageName, augmentBuilders);
628         }
629
630         final String augTypeName = augGenTypeName(augmentBuilders, targetTypeName);
631         final Type targetTypeRef = new ReferencedTypeImpl(targetPackageName, targetTypeName);
632         final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
633
634         final GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
635
636         augTypeBuilder.addImplementsType(Types.DATA_OBJECT);
637         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
638
639         augSchemaNodeToMethods(augmentPackageName, augTypeBuilder, augChildNodes);
640         augmentBuilders.put(augTypeName, augTypeBuilder);
641         return augTypeBuilder;
642     }
643
644     private List<Type> augmentationBodyToGenTypes(final String augBasePackageName,
645             final Set<DataSchemaNode> augChildNodes) {
646         final List<Type> genTypes = new ArrayList<>();
647         final List<DataNodeIterator> augSchemaIts = new ArrayList<>();
648         for (final DataSchemaNode childNode : augChildNodes) {
649             if (childNode instanceof DataNodeContainer) {
650                 augSchemaIts.add(new DataNodeIterator((DataNodeContainer) childNode));
651
652                 if (childNode instanceof ContainerSchemaNode) {
653                     genTypes.add(containerToGenType(augBasePackageName, (ContainerSchemaNode) childNode));
654                 } else if (childNode instanceof ListSchemaNode) {
655                     genTypes.addAll(listToGenType(augBasePackageName, (ListSchemaNode) childNode));
656                 }
657             } else if (childNode instanceof ChoiceNode) {
658                 final ChoiceNode choice = (ChoiceNode) childNode;
659                 for (final ChoiceCaseNode caseNode : choice.getCases()) {
660                     augSchemaIts.add(new DataNodeIterator(caseNode));
661                 }
662                 genTypes.addAll(choiceToGeneratedType(augBasePackageName, (ChoiceNode) childNode));
663             }
664         }
665
666         for (final DataNodeIterator it : augSchemaIts) {
667             final List<ContainerSchemaNode> augContainers = it.allContainers();
668             final List<ListSchemaNode> augLists = it.allLists();
669             final List<ChoiceNode> augChoices = it.allChoices();
670
671             if (augContainers != null) {
672                 for (final ContainerSchemaNode container : augContainers) {
673                     genTypes.add(containerToGenType(augBasePackageName, container));
674                 }
675             }
676             if (augLists != null) {
677                 for (final ListSchemaNode list : augLists) {
678                     genTypes.addAll(listToGenType(augBasePackageName, list));
679                 }
680             }
681             if (augChoices != null) {
682                 for (final ChoiceNode choice : augChoices) {
683                     genTypes.addAll(choiceToGeneratedType(augBasePackageName, choice));
684                 }
685             }
686         }
687         return genTypes;
688     }
689
690     private String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
691         String augTypeName = genTypeName;
692
693         int index = 1;
694         while ((builders != null) && builders.containsKey(genTypeName + index)) {
695             index++;
696         }
697         augTypeName += index;
698         return augTypeName;
699     }
700
701     private GeneratedType containerToGenType(final String basePackageName, ContainerSchemaNode containerNode) {
702         if (containerNode == null) {
703             return null;
704         }
705
706         final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
707         final Set<DataSchemaNode> schemaNodes = containerNode.getChildNodes();
708         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, containerNode);
709
710         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
711         return typeBuilder.toInstance();
712     }
713
714     private GeneratedTypeBuilder resolveDataSchemaNodes(final String basePackageName,
715             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
716         if ((schemaNodes != null) && (typeBuilder != null)) {
717             for (final DataSchemaNode schemaNode : schemaNodes) {
718                 if (schemaNode.isAugmenting() || schemaNode.isAddedByUses()) {
719                     continue;
720                 }
721                 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
722             }
723         }
724         return typeBuilder;
725     }
726
727     private GeneratedTypeBuilder augSchemaNodeToMethods(final String basePackageName,
728             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
729         if ((schemaNodes != null) && (typeBuilder != null)) {
730             for (final DataSchemaNode schemaNode : schemaNodes) {
731                 if (schemaNode.isAugmenting()) {
732                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
733                 }
734             }
735         }
736         return typeBuilder;
737     }
738
739     private void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode schemaNode,
740             final GeneratedTypeBuilder typeBuilder) {
741         if (schemaNode != null && typeBuilder != null) {
742             if (schemaNode instanceof LeafSchemaNode) {
743                 resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) schemaNode);
744             } else if (schemaNode instanceof LeafListSchemaNode) {
745                 resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
746             } else if (schemaNode instanceof ContainerSchemaNode) {
747                 resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
748             } else if (schemaNode instanceof ListSchemaNode) {
749                 resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
750             } else if (schemaNode instanceof ChoiceNode) {
751                 resolveChoiceSchemaNode(basePackageName, typeBuilder, (ChoiceNode) schemaNode);
752             }
753         }
754     }
755
756     private void resolveChoiceSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
757             final ChoiceNode choiceNode) {
758         if (basePackageName == null) {
759             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
760         }
761         if (typeBuilder == null) {
762             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
763         }
764         if (choiceNode == null) {
765             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
766         }
767
768         final String choiceName = choiceNode.getQName().getLocalName();
769         if (choiceName != null && !choiceNode.isAddedByUses()) {
770             final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
771             final GeneratedTypeBuilder choiceType = addDefaultInterfaceDefinition(packageName, choiceNode);
772             constructGetter(typeBuilder, choiceName, choiceNode.getDescription(), choiceType);
773         }
774     }
775
776     private List<GeneratedType> choiceToGeneratedType(final String basePackageName, final ChoiceNode choiceNode) {
777         if (basePackageName == null) {
778             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
779         }
780         if (choiceNode == null) {
781             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
782         }
783
784         final List<GeneratedType> generatedTypes = new ArrayList<>();
785         final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
786         final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
787         choiceTypeBuilder.addImplementsType(Types.DATA_OBJECT);
788         final GeneratedType choiceType = choiceTypeBuilder.toInstance();
789
790         generatedTypes.add(choiceType);
791         final Set<ChoiceCaseNode> caseNodes = choiceNode.getCases();
792         if ((caseNodes != null) && !caseNodes.isEmpty()) {
793             generatedTypes.addAll(generateTypesFromChoiceCases(basePackageName, choiceType, caseNodes));
794         }
795         return generatedTypes;
796     }
797
798     private List<GeneratedType> generateTypesFromChoiceCases(final String basePackageName, final Type refChoiceType,
799             final Set<ChoiceCaseNode> caseNodes) {
800         if (basePackageName == null) {
801             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
802         }
803         if (refChoiceType == null) {
804             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
805         }
806         if (caseNodes == null) {
807             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
808         }
809
810         final List<GeneratedType> generatedTypes = new ArrayList<>();
811         for (final ChoiceCaseNode caseNode : caseNodes) {
812             if (caseNode != null && !caseNode.isAddedByUses()) {
813                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
814                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
815                 caseTypeBuilder.addImplementsType(refChoiceType);
816
817                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
818                 if (childNodes != null) {
819                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
820                 }
821                 generatedTypes.add(caseTypeBuilder.toInstance());
822             }
823         }
824
825         return generatedTypes;
826     }
827
828     private List<GeneratedType> generateTypesFromAugmentedChoiceCases(final String basePackageName,
829             final Type refChoiceType, final Set<ChoiceCaseNode> caseNodes) {
830         if (basePackageName == null) {
831             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
832         }
833         if (refChoiceType == null) {
834             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
835         }
836         if (caseNodes == null) {
837             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
838         }
839
840         final List<GeneratedType> generatedTypes = new ArrayList<>();
841         for (final ChoiceCaseNode caseNode : caseNodes) {
842             if (caseNode != null && caseNode.isAugmenting()) {
843                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
844                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
845                 caseTypeBuilder.addImplementsType(refChoiceType);
846
847                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
848                 if (childNodes != null) {
849                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
850                 }
851                 generatedTypes.add(caseTypeBuilder.toInstance());
852             }
853         }
854
855         return generatedTypes;
856     }
857
858     private boolean resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
859         if ((leaf != null) && (typeBuilder != null)) {
860             final String leafName = leaf.getQName().getLocalName();
861             String leafDesc = leaf.getDescription();
862             if (leafDesc == null) {
863                 leafDesc = "";
864             }
865
866             if (leafName != null && !leaf.isAddedByUses()) {
867                 final TypeDefinition<?> typeDef = leaf.getType();
868
869                 Type returnType = null;
870                 if (typeDef instanceof EnumTypeDefinition) {
871                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
872                     final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
873                     final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName,
874                             typeBuilder);
875
876                     if (enumBuilder != null) {
877                         returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
878                     }
879                     ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
880                 } else if (typeDef instanceof UnionType) {
881                     GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
882                     if (genTOBuilder != null) {
883                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
884                     }
885                 } else if (typeDef instanceof BitsTypeDefinition) {
886                     GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
887                     if (genTOBuilder != null) {
888                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
889                     }
890                 } else {
891                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
892                 }
893                 if (returnType != null) {
894                     constructGetter(typeBuilder, leafName, leafDesc, returnType);
895                     return true;
896                 }
897             }
898         }
899         return false;
900     }
901
902     private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
903             boolean isReadOnly) {
904         if ((leaf != null) && (toBuilder != null)) {
905             final String leafName = leaf.getQName().getLocalName();
906             String leafDesc = leaf.getDescription();
907             if (leafDesc == null) {
908                 leafDesc = "";
909             }
910
911             if (leafName != null && !leaf.isAddedByUses()) {
912                 final TypeDefinition<?> typeDef = leaf.getType();
913
914                 // TODO: properly resolve enum types
915                 final Type returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
916
917                 if (returnType != null) {
918                     final GeneratedPropertyBuilder propBuilder = toBuilder.addProperty(parseToClassName(leafName));
919
920                     propBuilder.setReadOnly(isReadOnly);
921                     propBuilder.setReturnType(returnType);
922                     propBuilder.setComment(leafDesc);
923
924                     toBuilder.addEqualsIdentity(propBuilder);
925                     toBuilder.addHashIdentity(propBuilder);
926                     toBuilder.addToStringProperty(propBuilder);
927
928                     return true;
929                 }
930             }
931         }
932         return false;
933     }
934
935     private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node) {
936         if ((node != null) && (typeBuilder != null)) {
937             final String nodeName = node.getQName().getLocalName();
938             String nodeDesc = node.getDescription();
939             if (nodeDesc == null) {
940                 nodeDesc = "";
941             }
942
943             if (nodeName != null && !node.isAddedByUses()) {
944                 final TypeDefinition<?> type = node.getType();
945                 final Type listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type));
946
947                 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
948                 return true;
949             }
950         }
951         return false;
952     }
953
954     private boolean resolveContainerSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
955             final ContainerSchemaNode containerNode) {
956         if ((containerNode != null) && (typeBuilder != null)) {
957             final String nodeName = containerNode.getQName().getLocalName();
958
959             if (nodeName != null && !containerNode.isAddedByUses()) {
960                 final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
961
962                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, containerNode);
963                 constructGetter(typeBuilder, nodeName, containerNode.getDescription(), rawGenType);
964
965                 return true;
966             }
967         }
968         return false;
969     }
970
971     private boolean resolveListSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
972             final ListSchemaNode schemaNode) {
973         if ((schemaNode != null) && (typeBuilder != null)) {
974             final String listName = schemaNode.getQName().getLocalName();
975
976             if (listName != null && !schemaNode.isAddedByUses()) {
977                 final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath());
978                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, schemaNode);
979                 constructGetter(typeBuilder, listName, schemaNode.getDescription(), Types.listTypeFor(rawGenType));
980                 return true;
981             }
982         }
983         return false;
984     }
985
986     /**
987      * Method instantiates new Generated Type Builder and sets the implements
988      * definitions of Data Object and Augmentable.
989      * 
990      * @param packageName
991      *            Generated Type Package Name
992      * @param schemaNode
993      *            Schema Node definition
994      * @return Generated Type Builder instance for Schema Node definition
995      */
996     private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
997         final GeneratedTypeBuilder builder = addRawInterfaceDefinition(packageName, schemaNode, "");
998         builder.addImplementsType(Types.DATA_OBJECT);
999         if (!(schemaNode instanceof GroupingDefinition)) {
1000             builder.addImplementsType(Types.augmentableTypeFor(builder));
1001         }
1002
1003         if (schemaNode instanceof DataNodeContainer) {
1004             addInterfaceDefinition((DataNodeContainer) schemaNode, builder);
1005         }
1006
1007         return builder;
1008     }
1009
1010     /**
1011      * 
1012      * @param packageName
1013      * @param schemaNode
1014      * @return
1015      */
1016     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
1017         return addRawInterfaceDefinition(packageName, schemaNode, "");
1018     }
1019
1020     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
1021             final String prefix) {
1022         if (schemaNode == null) {
1023             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
1024         }
1025         if (packageName == null) {
1026             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1027         }
1028         if (schemaNode.getQName() == null) {
1029             throw new IllegalArgumentException("QName for Data Schema Node cannot be NULL!");
1030         }
1031         final String schemaNodeName = schemaNode.getQName().getLocalName();
1032         if (schemaNodeName == null) {
1033             throw new IllegalArgumentException("Local Name of QName for Data Schema Node cannot be NULL!");
1034         }
1035
1036         final String genTypeName;
1037         if (prefix == null) {
1038             genTypeName = parseToClassName(schemaNodeName);
1039         } else {
1040             genTypeName = prefix + parseToClassName(schemaNodeName);
1041         }
1042
1043         final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1044         if (!genTypeBuilders.containsKey(packageName)) {
1045             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
1046             builders.put(genTypeName, newType);
1047             genTypeBuilders.put(packageName, builders);
1048         } else {
1049             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1050             if (!builders.containsKey(genTypeName)) {
1051                 builders.put(genTypeName, newType);
1052             }
1053         }
1054         return newType;
1055     }
1056
1057     private String getterMethodName(final String methodName) {
1058         final StringBuilder method = new StringBuilder();
1059         method.append("get");
1060         method.append(parseToClassName(methodName));
1061         return method.toString();
1062     }
1063
1064     private String setterMethodName(final String methodName) {
1065         final StringBuilder method = new StringBuilder();
1066         method.append("set");
1067         method.append(parseToClassName(methodName));
1068         return method.toString();
1069     }
1070
1071     private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
1072             final String schemaNodeName, final String comment, final Type returnType) {
1073         final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName));
1074
1075         getMethod.setComment(comment);
1076         getMethod.setReturnType(returnType);
1077
1078         return getMethod;
1079     }
1080
1081     private MethodSignatureBuilder constructSetter(final GeneratedTypeBuilder interfaceBuilder,
1082             final String schemaNodeName, final String comment, final Type parameterType) {
1083         final MethodSignatureBuilder setMethod = interfaceBuilder.addMethod(setterMethodName(schemaNodeName));
1084
1085         setMethod.setComment(comment);
1086         setMethod.addParameter(parameterType, parseToValidParamName(schemaNodeName));
1087         setMethod.setReturnType(Types.voidType());
1088
1089         return setMethod;
1090     }
1091
1092     private List<Type> listToGenType(final String basePackageName, final ListSchemaNode list) {
1093         if (basePackageName == null) {
1094             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1095         }
1096         if (list == null) {
1097             throw new IllegalArgumentException("List Schema Node cannot be NULL!");
1098         }
1099
1100         final String packageName = packageNameForGeneratedType(basePackageName, list.getPath());
1101         final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(packageName, list);
1102         final List<String> listKeys = listKeys(list);
1103         GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, list, listKeys);
1104
1105         final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
1106
1107         for (final DataSchemaNode schemaNode : schemaNodes) {
1108             if (schemaNode.isAugmenting()) {
1109                 continue;
1110             }
1111             addSchemaNodeToListBuilders(basePackageName, schemaNode, typeBuilder, genTOBuilder, listKeys);
1112         }
1113         return typeBuildersToGenTypes(typeBuilder, genTOBuilder);
1114     }
1115
1116     private void addSchemaNodeToListBuilders(final String basePackageName, final DataSchemaNode schemaNode,
1117             final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys) {
1118         if (schemaNode == null) {
1119             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
1120         }
1121
1122         if (typeBuilder == null) {
1123             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1124         }
1125
1126         if (schemaNode instanceof LeafSchemaNode) {
1127             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1128             if (!isPartOfListKey(leaf, listKeys)) {
1129                 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1130             } else {
1131                 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1132             }
1133         } else if (schemaNode instanceof LeafListSchemaNode) {
1134             resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
1135         } else if (schemaNode instanceof ContainerSchemaNode) {
1136             resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
1137         } else if (schemaNode instanceof ListSchemaNode) {
1138             resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
1139         }
1140     }
1141
1142     private List<Type> typeBuildersToGenTypes(final GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1143         final List<Type> genTypes = new ArrayList<>();
1144         if (typeBuilder == null) {
1145             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1146         }
1147
1148         if (genTOBuilder != null) {
1149             final GeneratedTransferObject genTO = genTOBuilder.toInstance();
1150             constructGetter(typeBuilder, genTO.getName(), "Returns Primary Key of Yang List Type", genTO);
1151             genTypes.add(genTO);
1152         }
1153         genTypes.add(typeBuilder.toInstance());
1154         return genTypes;
1155     }
1156
1157     /**
1158      * @param list
1159      * @return
1160      */
1161     private GeneratedTOBuilder resolveListKey(final String packageName, final ListSchemaNode list) {
1162         final String listName = list.getQName().getLocalName() + "Key";
1163         return schemaNodeToTransferObjectBuilder(packageName, list, listName);
1164     }
1165
1166     private boolean isPartOfListKey(final LeafSchemaNode leaf, final List<String> keys) {
1167         if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
1168             final String leafName = leaf.getQName().getLocalName();
1169             if (keys.contains(leafName)) {
1170                 return true;
1171             }
1172         }
1173         return false;
1174     }
1175
1176     private List<String> listKeys(final ListSchemaNode list) {
1177         final List<String> listKeys = new ArrayList<>();
1178
1179         if (list.getKeyDefinition() != null) {
1180             final List<QName> keyDefinitions = list.getKeyDefinition();
1181
1182             for (final QName keyDefinition : keyDefinitions) {
1183                 listKeys.add(keyDefinition.getLocalName());
1184             }
1185         }
1186         return listKeys;
1187     }
1188
1189     private GeneratedTypeBuilder resolveListTypeBuilder(final String packageName, final ListSchemaNode list) {
1190         if (packageName == null) {
1191             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1192         }
1193         if (list == null) {
1194             throw new IllegalArgumentException("List Schema Node cannot be NULL!");
1195         }
1196
1197         final String schemaNodeName = list.getQName().getLocalName();
1198         final String genTypeName = parseToClassName(schemaNodeName);
1199
1200         GeneratedTypeBuilder typeBuilder = null;
1201         final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1202         if (builders != null) {
1203             typeBuilder = builders.get(genTypeName);
1204         }
1205         if (typeBuilder == null) {
1206             typeBuilder = addDefaultInterfaceDefinition(packageName, list);
1207         }
1208         return typeBuilder;
1209     }
1210
1211     private GeneratedTOBuilder resolveListKeyTOBuilder(final String packageName, final ListSchemaNode list,
1212             final List<String> listKeys) {
1213         GeneratedTOBuilder genTOBuilder = null;
1214         if (listKeys.size() > 0) {
1215             genTOBuilder = resolveListKey(packageName, list);
1216         }
1217         return genTOBuilder;
1218     }
1219
1220     private GeneratedTOBuilder addEnclosedTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
1221             String leafName) {
1222         String className = parseToClassName(leafName);
1223         GeneratedTOBuilder genTOBuilder = null;
1224         if (typeDef instanceof UnionType) {
1225             genTOBuilder = ((TypeProviderImpl) typeProvider).addUnionGeneratedTypeDefinition(
1226                     typeBuilder.getFullyQualifiedName(), typeDef, className);
1227         } else if (typeDef instanceof BitsTypeDefinition) {
1228             genTOBuilder = ((TypeProviderImpl) typeProvider).bitsTypedefToTransferObject(
1229                     typeBuilder.getFullyQualifiedName(), typeDef, className);
1230         }
1231         if (genTOBuilder != null) {
1232             typeBuilder.addEnclosingTransferObject(genTOBuilder);
1233             return genTOBuilder;
1234         }
1235         return null;
1236
1237     }
1238
1239     /**
1240      * Adds the implemented types to type builder. The method passes through the
1241      * list of elements which contains {@code dataNodeContainer} and adds them
1242      * as <i>implements type</i> to <code>builder</code>
1243      * 
1244      * @param dataNodeContainer
1245      *            element which contains the list of used YANG groupings
1246      * @param builder
1247      *            builder to which are added implemented types according to
1248      *            <code>dataNodeContainer</code>
1249      * @return generated type builder which contains implemented types
1250      */
1251     private GeneratedTypeBuilder addInterfaceDefinition(final DataNodeContainer dataNodeContainer,
1252             final GeneratedTypeBuilder builder) {
1253         for (UsesNode usesNode : dataNodeContainer.getUses()) {
1254             if (usesNode.getGroupingPath() != null) {
1255                 GeneratedType genType = allGroupings.get(usesNode.getGroupingPath());
1256                 builder.addImplementsType(new ReferencedTypeImpl(genType.getPackageName(), genType.getName()));
1257             }
1258         }
1259         return builder;
1260     }
1261
1262 }