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