bcaf3a062a754e4ea5303723a4159a3226c75bdb
[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                 String rpcMethodName = parseToValidParamName(rpcName);
331                 MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
332
333                 final List<DataNodeIterator> rpcInOut = new ArrayList<>();
334
335                 ContainerSchemaNode input = rpc.getInput();
336                 ContainerSchemaNode output = rpc.getOutput();
337
338                 if (input != null) {
339                     rpcInOut.add(new DataNodeIterator(input));
340                     GeneratedTypeBuilder inType = addRawInterfaceDefinition(basePackageName, input, rpcName);
341                     resolveDataSchemaNodes(basePackageName, inType, input.getChildNodes());
342                     Type inTypeInstance = inType.toInstance();
343                     genRPCTypes.add(inTypeInstance);
344                     method.addParameter(inTypeInstance, "input");
345                 }
346
347                 Type outTypeInstance = Types.typeForClass(Void.class);
348                 if (output != null) {
349                     rpcInOut.add(new DataNodeIterator(output));
350
351                     GeneratedTypeBuilder outType = addRawInterfaceDefinition(basePackageName, output, rpcName);
352                     resolveDataSchemaNodes(basePackageName, outType, output.getChildNodes());
353                     outTypeInstance = outType.toInstance();
354                     genRPCTypes.add(outTypeInstance);
355
356                 }
357
358                 final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
359                 method.setReturnType(Types.parameterizedTypeFor(future, rpcRes));
360                 for (DataNodeIterator it : rpcInOut) {
361                     List<ContainerSchemaNode> nContainers = it.allContainers();
362                     if ((nContainers != null) && !nContainers.isEmpty()) {
363                         for (final ContainerSchemaNode container : nContainers) {
364                             genRPCTypes.add(containerToGenType(basePackageName, container));
365                         }
366                     }
367                     List<ListSchemaNode> nLists = it.allLists();
368                     if ((nLists != null) && !nLists.isEmpty()) {
369                         for (final ListSchemaNode list : nLists) {
370                             genRPCTypes.addAll(listToGenType(basePackageName, list));
371                         }
372                     }
373                 }
374             }
375         }
376         genRPCTypes.add(interfaceBuilder.toInstance());
377         return genRPCTypes;
378     }
379
380     private List<Type> allNotificationsToGenType(final Module module) {
381         if (module == null) {
382             throw new IllegalArgumentException("Module reference cannot be NULL!");
383         }
384
385         if (module.getName() == null) {
386             throw new IllegalArgumentException("Module name cannot be NULL!");
387         }
388
389         if (module.getChildNodes() == null) {
390             throw new IllegalArgumentException("Reference to Set of Notification Definitions in module "
391                     + module.getName() + " cannot be NULL!");
392         }
393
394         final String basePackageName = moduleNamespaceToPackageName(module);
395         final List<Type> genNotifyTypes = new ArrayList<>();
396         final Set<NotificationDefinition> notifications = module.getNotifications();
397
398         for (final NotificationDefinition notification : notifications) {
399             if (notification != null) {
400                 DataNodeIterator it = new DataNodeIterator(notification);
401
402                 // Containers
403                 for (ContainerSchemaNode node : it.allContainers()) {
404                     genNotifyTypes.add(containerToGenType(basePackageName, node));
405                 }
406                 // Lists
407                 for (ListSchemaNode node : it.allLists()) {
408                     genNotifyTypes.addAll(listToGenType(basePackageName, node));
409                 }
410                 final GeneratedTypeBuilder notificationTypeBuilder = addDefaultInterfaceDefinition(basePackageName,
411                         notification);
412                 notificationTypeBuilder.addImplementsType(Types.typeForClass(Notification.class));
413                 // Notification object
414                 resolveDataSchemaNodes(basePackageName, notificationTypeBuilder, notification.getChildNodes());
415                 genNotifyTypes.add(notificationTypeBuilder.toInstance());
416             }
417         }
418         return genNotifyTypes;
419     }
420
421     private List<Type> allIdentitiesToGenTypes(final Module module, final SchemaContext context) {
422         List<Type> genTypes = new ArrayList<>();
423
424         final Set<IdentitySchemaNode> schemaIdentities = module.getIdentities();
425
426         final String basePackageName = moduleNamespaceToPackageName(module);
427
428         if (schemaIdentities != null && !schemaIdentities.isEmpty()) {
429             for (final IdentitySchemaNode identity : schemaIdentities) {
430                 genTypes.add(identityToGenType(basePackageName, identity, context));
431             }
432         }
433         return genTypes;
434     }
435
436     private GeneratedType identityToGenType(final String basePackageName, final IdentitySchemaNode identity,
437             final SchemaContext context) {
438         if (identity == null) {
439             return null;
440         }
441
442         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
443         final String genTypeName = parseToClassName(identity.getQName().getLocalName());
444         final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTypeName);
445
446         IdentitySchemaNode baseIdentity = identity.getBaseIdentity();
447         if (baseIdentity != null) {
448             Module baseIdentityParentModule = SchemaContextUtil.findParentModule(context, baseIdentity);
449
450             final String returnTypePkgName = moduleNamespaceToPackageName(baseIdentityParentModule);
451             final String returnTypeName = parseToClassName(baseIdentity.getQName().getLocalName());
452
453             GeneratedTransferObject gto = new GeneratedTOBuilderImpl(returnTypePkgName, returnTypeName).toInstance();
454             newType.setExtendsType(gto);
455         } else {
456             newType.setExtendsType(Types.getBaseIdentityTO());
457         }
458         newType.setAbstract(true);
459         return newType.toInstance();
460     }
461
462     private List<Type> allGroupingsToGenTypes(final Module module) {
463         final List<Type> genTypes = new ArrayList<>();
464         final String basePackageName = moduleNamespaceToPackageName(module);
465         final Set<GroupingDefinition> groupings = module.getGroupings();
466         if (groupings != null && !groupings.isEmpty()) {
467             for (final GroupingDefinition grouping : groupings) {
468                 genTypes.add(groupingToGenType(basePackageName, grouping));
469             }
470         }
471         return genTypes;
472     }
473
474     private GeneratedType groupingToGenType(final String basePackageName, GroupingDefinition grouping) {
475         if (grouping == null) {
476             return null;
477         }
478
479         final String packageName = packageNameForGeneratedType(basePackageName, grouping.getPath());
480         final Set<DataSchemaNode> schemaNodes = grouping.getChildNodes();
481         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, grouping);
482
483         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
484         return typeBuilder.toInstance();
485     }
486
487     private EnumTypeDefinition enumTypeDefFromExtendedType(final TypeDefinition<?> typeDefinition) {
488         if (typeDefinition != null) {
489             if (typeDefinition.getBaseType() instanceof EnumTypeDefinition) {
490                 return (EnumTypeDefinition) typeDefinition.getBaseType();
491             } else if (typeDefinition.getBaseType() instanceof ExtendedType) {
492                 return enumTypeDefFromExtendedType(typeDefinition.getBaseType());
493             }
494         }
495         return null;
496     }
497
498     private EnumBuilder resolveInnerEnumFromTypeDefinition(final EnumTypeDefinition enumTypeDef, final String enumName,
499             final GeneratedTypeBuilder typeBuilder) {
500         if ((enumTypeDef != null) && (typeBuilder != null) && (enumTypeDef.getQName() != null)
501                 && (enumTypeDef.getQName().getLocalName() != null)) {
502
503             final String enumerationName = parseToClassName(enumName);
504             final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
505
506             if (enumBuilder != null) {
507                 final List<EnumPair> enums = enumTypeDef.getValues();
508                 if (enums != null) {
509                     int listIndex = 0;
510                     for (final EnumPair enumPair : enums) {
511                         if (enumPair != null) {
512                             final String enumPairName = parseToClassName(enumPair.getName());
513                             Integer enumPairValue = enumPair.getValue();
514
515                             if (enumPairValue == null) {
516                                 enumPairValue = listIndex;
517                             }
518                             enumBuilder.addValue(enumPairName, enumPairValue);
519                             listIndex++;
520                         }
521                     }
522                 }
523                 return enumBuilder;
524             }
525         }
526         return null;
527     }
528
529     private GeneratedTypeBuilder moduleTypeBuilder(final Module module, final String postfix) {
530         if (module == null) {
531             throw new IllegalArgumentException("Module reference cannot be NULL!");
532         }
533         String packageName = moduleNamespaceToPackageName(module);
534         final String moduleName = parseToClassName(module.getName()) + postfix;
535
536         return new GeneratedTypeBuilderImpl(packageName, moduleName);
537
538     }
539
540     private List<Type> augmentationToGenTypes(final String augmentPackageName, final AugmentationSchema augSchema) {
541         if (augmentPackageName == null) {
542             throw new IllegalArgumentException("Package Name cannot be NULL!");
543         }
544         if (augSchema == null) {
545             throw new IllegalArgumentException("Augmentation Schema cannot be NULL!");
546         }
547         if (augSchema.getTargetPath() == null) {
548             throw new IllegalStateException("Augmentation Schema does not contain Target Path (Target Path is NULL).");
549         }
550
551         final List<Type> genTypes = new ArrayList<>();
552
553         // EVERY augmented interface will extends Augmentation<T> interface
554         // and DataObject interface!!!
555         final SchemaPath targetPath = augSchema.getTargetPath();
556         final DataSchemaNode targetSchemaNode = findDataSchemaNode(schemaContext, targetPath);
557         if ((targetSchemaNode != null) && (targetSchemaNode.getQName() != null)
558                 && (targetSchemaNode.getQName().getLocalName() != null)) {
559             final Module targetModule = findParentModule(schemaContext, targetSchemaNode);
560             final String targetBasePackage = moduleNamespaceToPackageName(targetModule);
561             final String targetPackageName = packageNameForGeneratedType(targetBasePackage, targetSchemaNode.getPath());
562             final String targetSchemaNodeName = targetSchemaNode.getQName().getLocalName();
563             final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
564
565             if (!(targetSchemaNode instanceof ChoiceNode)) {
566                 final GeneratedTypeBuilder augTypeBuilder = addRawAugmentGenTypeDefinition(augmentPackageName,
567                         targetPackageName, targetSchemaNodeName, augSchema);
568                 final GeneratedType augType = augTypeBuilder.toInstance();
569                 genTypes.add(augType);
570             } else {
571                 final Type refChoiceType = new ReferencedTypeImpl(targetPackageName,
572                         parseToClassName(targetSchemaNodeName));
573                 final ChoiceNode choiceTarget = (ChoiceNode) targetSchemaNode;
574                 final Set<ChoiceCaseNode> choiceCaseNodes = choiceTarget.getCases();
575                 genTypes.addAll(augmentCasesToGenTypes(augmentPackageName, refChoiceType, choiceCaseNodes));
576             }
577             genTypes.addAll(augmentationBodyToGenTypes(augmentPackageName, augChildNodes));
578         }
579         return genTypes;
580     }
581
582     private List<GeneratedType> augmentCasesToGenTypes(final String augmentPackageName, final Type refChoiceType,
583             final Set<ChoiceCaseNode> choiceCaseNodes) {
584         if (augmentPackageName == null) {
585             throw new IllegalArgumentException("Augment Package Name string cannot be NULL!");
586         }
587         if (choiceCaseNodes == null) {
588             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
589         }
590         final List<GeneratedType> genTypes = generateTypesFromAugmentedChoiceCases(augmentPackageName, refChoiceType,
591                 choiceCaseNodes);
592         return genTypes;
593     }
594
595     private GeneratedTypeBuilder addRawAugmentGenTypeDefinition(final String augmentPackageName,
596             final String targetPackageName, final String targetSchemaNodeName, final AugmentationSchema augSchema) {
597         final String targetTypeName = parseToClassName(targetSchemaNodeName);
598         Map<String, GeneratedTypeBuilder> augmentBuilders = genTypeBuilders.get(augmentPackageName);
599         if (augmentBuilders == null) {
600             augmentBuilders = new HashMap<>();
601             genTypeBuilders.put(augmentPackageName, augmentBuilders);
602         }
603
604         final String augTypeName = augGenTypeName(augmentBuilders, targetTypeName);
605         final Type targetTypeRef = new ReferencedTypeImpl(targetPackageName, targetTypeName);
606         final Set<DataSchemaNode> augChildNodes = augSchema.getChildNodes();
607
608         final GeneratedTypeBuilder augTypeBuilder = new GeneratedTypeBuilderImpl(augmentPackageName, augTypeName);
609
610         augTypeBuilder.addImplementsType(Types.DATA_OBJECT);
611         augTypeBuilder.addImplementsType(Types.augmentationTypeFor(targetTypeRef));
612
613         augSchemaNodeToMethods(augmentPackageName, augTypeBuilder, augChildNodes);
614         augmentBuilders.put(augTypeName, augTypeBuilder);
615         return augTypeBuilder;
616     }
617
618     private List<Type> augmentationBodyToGenTypes(final String augBasePackageName,
619             final Set<DataSchemaNode> augChildNodes) {
620         final List<Type> genTypes = new ArrayList<>();
621         final List<DataNodeIterator> augSchemaIts = new ArrayList<>();
622         for (final DataSchemaNode childNode : augChildNodes) {
623             if (childNode instanceof DataNodeContainer) {
624                 augSchemaIts.add(new DataNodeIterator((DataNodeContainer) childNode));
625
626                 if (childNode instanceof ContainerSchemaNode) {
627                     genTypes.add(containerToGenType(augBasePackageName, (ContainerSchemaNode) childNode));
628                 } else if (childNode instanceof ListSchemaNode) {
629                     genTypes.addAll(listToGenType(augBasePackageName, (ListSchemaNode) childNode));
630                 }
631             } else if (childNode instanceof ChoiceNode) {
632                 final ChoiceNode choice = (ChoiceNode) childNode;
633                 for (final ChoiceCaseNode caseNode : choice.getCases()) {
634                     augSchemaIts.add(new DataNodeIterator(caseNode));
635                 }
636                 genTypes.addAll(choiceToGeneratedType(augBasePackageName, (ChoiceNode) childNode));
637             }
638         }
639
640         for (final DataNodeIterator it : augSchemaIts) {
641             final List<ContainerSchemaNode> augContainers = it.allContainers();
642             final List<ListSchemaNode> augLists = it.allLists();
643             final List<ChoiceNode> augChoices = it.allChoices();
644
645             if (augContainers != null) {
646                 for (final ContainerSchemaNode container : augContainers) {
647                     genTypes.add(containerToGenType(augBasePackageName, container));
648                 }
649             }
650             if (augLists != null) {
651                 for (final ListSchemaNode list : augLists) {
652                     genTypes.addAll(listToGenType(augBasePackageName, list));
653                 }
654             }
655             if (augChoices != null) {
656                 for (final ChoiceNode choice : augChoices) {
657                     genTypes.addAll(choiceToGeneratedType(augBasePackageName, choice));
658                 }
659             }
660         }
661         return genTypes;
662     }
663
664     private String augGenTypeName(final Map<String, GeneratedTypeBuilder> builders, final String genTypeName) {
665         String augTypeName = genTypeName;
666
667         int index = 1;
668         while ((builders != null) && builders.containsKey(genTypeName + index)) {
669             index++;
670         }
671         augTypeName += index;
672         return augTypeName;
673     }
674
675     private GeneratedType containerToGenType(final String basePackageName, ContainerSchemaNode containerNode) {
676         if (containerNode == null) {
677             return null;
678         }
679
680         final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
681         final Set<DataSchemaNode> schemaNodes = containerNode.getChildNodes();
682         final GeneratedTypeBuilder typeBuilder = addDefaultInterfaceDefinition(packageName, containerNode);
683
684         resolveDataSchemaNodes(basePackageName, typeBuilder, schemaNodes);
685         return typeBuilder.toInstance();
686     }
687
688     private GeneratedTypeBuilder resolveDataSchemaNodes(final String basePackageName,
689             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
690         if ((schemaNodes != null) && (typeBuilder != null)) {
691             for (final DataSchemaNode schemaNode : schemaNodes) {
692                 if (schemaNode.isAugmenting()) {
693                     continue;
694                 }
695                 addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
696             }
697         }
698         return typeBuilder;
699     }
700
701     private GeneratedTypeBuilder augSchemaNodeToMethods(final String basePackageName,
702             final GeneratedTypeBuilder typeBuilder, final Set<DataSchemaNode> schemaNodes) {
703         if ((schemaNodes != null) && (typeBuilder != null)) {
704             for (final DataSchemaNode schemaNode : schemaNodes) {
705                 if (schemaNode.isAugmenting()) {
706                     addSchemaNodeToBuilderAsMethod(basePackageName, schemaNode, typeBuilder);
707                 }
708             }
709         }
710         return typeBuilder;
711     }
712
713     private void addSchemaNodeToBuilderAsMethod(final String basePackageName, final DataSchemaNode schemaNode,
714             final GeneratedTypeBuilder typeBuilder) {
715         if (schemaNode != null && typeBuilder != null) {
716             if (schemaNode instanceof LeafSchemaNode) {
717                 resolveLeafSchemaNodeAsMethod(typeBuilder, (LeafSchemaNode) schemaNode);
718             } else if (schemaNode instanceof LeafListSchemaNode) {
719                 resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
720             } else if (schemaNode instanceof ContainerSchemaNode) {
721                 resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
722             } else if (schemaNode instanceof ListSchemaNode) {
723                 resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
724             } else if (schemaNode instanceof ChoiceNode) {
725                 resolveChoiceSchemaNode(basePackageName, typeBuilder, (ChoiceNode) schemaNode);
726             }
727         }
728     }
729
730     private void resolveChoiceSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
731             final ChoiceNode choiceNode) {
732         if (basePackageName == null) {
733             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
734         }
735         if (typeBuilder == null) {
736             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
737         }
738         if (choiceNode == null) {
739             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
740         }
741
742         final String choiceName = choiceNode.getQName().getLocalName();
743         if (choiceName != null) {
744             final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
745             final GeneratedTypeBuilder choiceType = addDefaultInterfaceDefinition(packageName, choiceNode);
746             constructGetter(typeBuilder, choiceName, choiceNode.getDescription(), choiceType);
747         }
748     }
749
750     private List<GeneratedType> choiceToGeneratedType(final String basePackageName, final ChoiceNode choiceNode) {
751         if (basePackageName == null) {
752             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
753         }
754         if (choiceNode == null) {
755             throw new IllegalArgumentException("Choice Schema Node cannot be NULL!");
756         }
757
758         final List<GeneratedType> generatedTypes = new ArrayList<>();
759         final String packageName = packageNameForGeneratedType(basePackageName, choiceNode.getPath());
760         final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(packageName, choiceNode);
761         choiceTypeBuilder.addImplementsType(Types.DATA_OBJECT);
762         final GeneratedType choiceType = choiceTypeBuilder.toInstance();
763
764         generatedTypes.add(choiceType);
765         final Set<ChoiceCaseNode> caseNodes = choiceNode.getCases();
766         if ((caseNodes != null) && !caseNodes.isEmpty()) {
767             generatedTypes.addAll(generateTypesFromChoiceCases(basePackageName, choiceType, caseNodes));
768         }
769         return generatedTypes;
770     }
771
772     private List<GeneratedType> generateTypesFromChoiceCases(final String basePackageName, final Type refChoiceType,
773             final Set<ChoiceCaseNode> caseNodes) {
774         if (basePackageName == null) {
775             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
776         }
777         if (refChoiceType == null) {
778             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
779         }
780         if (caseNodes == null) {
781             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
782         }
783
784         final List<GeneratedType> generatedTypes = new ArrayList<>();
785         for (final ChoiceCaseNode caseNode : caseNodes) {
786             if (caseNode != null && !caseNode.isAddedByUses()) {
787                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
788                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
789                 caseTypeBuilder.addImplementsType(refChoiceType);
790
791                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
792                 if (childNodes != null) {
793                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
794                 }
795                 generatedTypes.add(caseTypeBuilder.toInstance());
796             }
797         }
798
799         return generatedTypes;
800     }
801
802     private List<GeneratedType> generateTypesFromAugmentedChoiceCases(final String basePackageName,
803             final Type refChoiceType, final Set<ChoiceCaseNode> caseNodes) {
804         if (basePackageName == null) {
805             throw new IllegalArgumentException("Base Package Name cannot be NULL!");
806         }
807         if (refChoiceType == null) {
808             throw new IllegalArgumentException("Referenced Choice Type cannot be NULL!");
809         }
810         if (caseNodes == null) {
811             throw new IllegalArgumentException("Set of Choice Case Nodes cannot be NULL!");
812         }
813
814         final List<GeneratedType> generatedTypes = new ArrayList<>();
815         for (final ChoiceCaseNode caseNode : caseNodes) {
816             if (caseNode != null && caseNode.isAugmenting()) {
817                 final String packageName = packageNameForGeneratedType(basePackageName, caseNode.getPath());
818                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(packageName, caseNode);
819                 caseTypeBuilder.addImplementsType(refChoiceType);
820
821                 final Set<DataSchemaNode> childNodes = caseNode.getChildNodes();
822                 if (childNodes != null) {
823                     resolveDataSchemaNodes(basePackageName, caseTypeBuilder, childNodes);
824                 }
825                 generatedTypes.add(caseTypeBuilder.toInstance());
826             }
827         }
828
829         return generatedTypes;
830     }
831
832     private boolean resolveLeafSchemaNodeAsMethod(final GeneratedTypeBuilder typeBuilder, final LeafSchemaNode leaf) {
833         if ((leaf != null) && (typeBuilder != null)) {
834             final String leafName = leaf.getQName().getLocalName();
835             String leafDesc = leaf.getDescription();
836             if (leafDesc == null) {
837                 leafDesc = "";
838             }
839
840             if (leafName != null) {
841                 final TypeDefinition<?> typeDef = leaf.getType();
842
843                 Type returnType = null;
844                 if (typeDef instanceof EnumTypeDefinition) {
845                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
846                     final EnumTypeDefinition enumTypeDef = enumTypeDefFromExtendedType(typeDef);
847                     final EnumBuilder enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, leafName,
848                             typeBuilder);
849
850                     if (enumBuilder != null) {
851                         returnType = new ReferencedTypeImpl(enumBuilder.getPackageName(), enumBuilder.getName());
852                     }
853                     ((TypeProviderImpl) typeProvider).putReferencedType(leaf.getPath(), returnType);
854                 } else if (typeDef instanceof UnionType) {
855                     GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
856                     if (genTOBuilder != null) {
857                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
858                     }
859                 } else if(typeDef instanceof BitsTypeDefinition) {
860                     GeneratedTOBuilder genTOBuilder = addEnclosedTOToTypeBuilder(typeDef, typeBuilder, leafName);
861                     if (genTOBuilder != null) {
862                         returnType = new ReferencedTypeImpl(genTOBuilder.getPackageName(), genTOBuilder.getName());
863                     }                    
864                 } else {
865                     returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
866                 }
867                 if (returnType != null) {
868                     constructGetter(typeBuilder, leafName, leafDesc, returnType);
869                     return true;
870                 }
871             }
872         }
873         return false;
874     }
875
876     private boolean resolveLeafSchemaNodeAsProperty(final GeneratedTOBuilder toBuilder, final LeafSchemaNode leaf,
877             boolean isReadOnly) {
878         if ((leaf != null) && (toBuilder != null)) {
879             final String leafName = leaf.getQName().getLocalName();
880             String leafDesc = leaf.getDescription();
881             if (leafDesc == null) {
882                 leafDesc = "";
883             }
884
885             if (leafName != null) {
886                 final TypeDefinition<?> typeDef = leaf.getType();
887
888                 // TODO: properly resolve enum types
889                 final Type returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef);
890
891                 if (returnType != null) {
892                     final GeneratedPropertyBuilder propBuilder = toBuilder.addProperty(parseToClassName(leafName));
893
894                     propBuilder.setReadOnly(isReadOnly);
895                     propBuilder.setReturnType(returnType);
896                     propBuilder.setComment(leafDesc);
897
898                     toBuilder.addEqualsIdentity(propBuilder);
899                     toBuilder.addHashIdentity(propBuilder);
900                     toBuilder.addToStringProperty(propBuilder);
901
902                     return true;
903                 }
904             }
905         }
906         return false;
907     }
908
909     private boolean resolveLeafListSchemaNode(final GeneratedTypeBuilder typeBuilder, final LeafListSchemaNode node) {
910         if ((node != null) && (typeBuilder != null)) {
911             final String nodeName = node.getQName().getLocalName();
912             String nodeDesc = node.getDescription();
913             if (nodeDesc == null) {
914                 nodeDesc = "";
915             }
916
917             if (nodeName != null) {
918                 final TypeDefinition<?> type = node.getType();
919                 final Type listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type));
920
921                 constructGetter(typeBuilder, nodeName, nodeDesc, listType);
922                 return true;
923             }
924         }
925         return false;
926     }
927
928     private boolean resolveContainerSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
929             final ContainerSchemaNode containerNode) {
930         if ((containerNode != null) && (typeBuilder != null)) {
931             final String nodeName = containerNode.getQName().getLocalName();
932
933             if (nodeName != null) {
934                 final String packageName = packageNameForGeneratedType(basePackageName, containerNode.getPath());
935
936                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, containerNode);
937                 constructGetter(typeBuilder, nodeName, containerNode.getDescription(), rawGenType);
938
939                 return true;
940             }
941         }
942         return false;
943     }
944
945     private boolean resolveListSchemaNode(final String basePackageName, final GeneratedTypeBuilder typeBuilder,
946             final ListSchemaNode schemaNode) {
947         if ((schemaNode != null) && (typeBuilder != null)) {
948             final String listName = schemaNode.getQName().getLocalName();
949
950             if (listName != null) {
951                 final String packageName = packageNameForGeneratedType(basePackageName, schemaNode.getPath());
952                 final GeneratedTypeBuilder rawGenType = addDefaultInterfaceDefinition(packageName, schemaNode);
953                 constructGetter(typeBuilder, listName, schemaNode.getDescription(), Types.listTypeFor(rawGenType));
954                 return true;
955             }
956         }
957         return false;
958     }
959
960     /**
961      * Method instantiates new Generated Type Builder and sets the implements
962      * definitions of Data Object and Augmentable.
963      * 
964      * @param packageName
965      *            Generated Type Package Name
966      * @param schemaNode
967      *            Schema Node definition
968      * @return Generated Type Builder instance for Schema Node definition
969      */
970     private GeneratedTypeBuilder addDefaultInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
971         final GeneratedTypeBuilder builder = addRawInterfaceDefinition(packageName, schemaNode, "");
972         builder.addImplementsType(Types.DATA_OBJECT);
973         builder.addImplementsType(Types.augmentableTypeFor(builder));
974         return builder;
975     }
976
977     /**
978      * 
979      * @param packageName
980      * @param schemaNode
981      * @return
982      */
983     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode) {
984         return addRawInterfaceDefinition(packageName, schemaNode, "");
985     }
986
987     private GeneratedTypeBuilder addRawInterfaceDefinition(final String packageName, final SchemaNode schemaNode,
988             final String prefix) {
989         if (schemaNode == null) {
990             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
991         }
992         if (packageName == null) {
993             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
994         }
995         if (schemaNode.getQName() == null) {
996             throw new IllegalArgumentException("QName for Data Schema Node cannot be NULL!");
997         }
998         final String schemaNodeName = schemaNode.getQName().getLocalName();
999         if (schemaNodeName == null) {
1000             throw new IllegalArgumentException("Local Name of QName for Data Schema Node cannot be NULL!");
1001         }
1002
1003         final String genTypeName;
1004         if (prefix == null) {
1005             genTypeName = parseToClassName(schemaNodeName);
1006         } else {
1007             genTypeName = prefix + parseToClassName(schemaNodeName);
1008         }
1009
1010         final GeneratedTypeBuilder newType = new GeneratedTypeBuilderImpl(packageName, genTypeName);
1011         if (!genTypeBuilders.containsKey(packageName)) {
1012             final Map<String, GeneratedTypeBuilder> builders = new HashMap<>();
1013             builders.put(genTypeName, newType);
1014             genTypeBuilders.put(packageName, builders);
1015         } else {
1016             final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1017             if (!builders.containsKey(genTypeName)) {
1018                 builders.put(genTypeName, newType);
1019             }
1020         }
1021         return newType;
1022     }
1023
1024     private String getterMethodName(final String methodName) {
1025         final StringBuilder method = new StringBuilder();
1026         method.append("get");
1027         method.append(parseToClassName(methodName));
1028         return method.toString();
1029     }
1030
1031     private String setterMethodName(final String methodName) {
1032         final StringBuilder method = new StringBuilder();
1033         method.append("set");
1034         method.append(parseToClassName(methodName));
1035         return method.toString();
1036     }
1037
1038     private MethodSignatureBuilder constructGetter(final GeneratedTypeBuilder interfaceBuilder,
1039             final String schemaNodeName, final String comment, final Type returnType) {
1040         final MethodSignatureBuilder getMethod = interfaceBuilder.addMethod(getterMethodName(schemaNodeName));
1041
1042         getMethod.setComment(comment);
1043         getMethod.setReturnType(returnType);
1044
1045         return getMethod;
1046     }
1047
1048     private MethodSignatureBuilder constructSetter(final GeneratedTypeBuilder interfaceBuilder,
1049             final String schemaNodeName, final String comment, final Type parameterType) {
1050         final MethodSignatureBuilder setMethod = interfaceBuilder.addMethod(setterMethodName(schemaNodeName));
1051
1052         setMethod.setComment(comment);
1053         setMethod.addParameter(parameterType, parseToValidParamName(schemaNodeName));
1054         setMethod.setReturnType(Types.voidType());
1055
1056         return setMethod;
1057     }
1058
1059     private List<Type> listToGenType(final String basePackageName, final ListSchemaNode list) {
1060         if (basePackageName == null) {
1061             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1062         }
1063         if (list == null) {
1064             throw new IllegalArgumentException("List Schema Node cannot be NULL!");
1065         }
1066
1067         final String packageName = packageNameForGeneratedType(basePackageName, list.getPath());
1068         final GeneratedTypeBuilder typeBuilder = resolveListTypeBuilder(packageName, list);
1069         final List<String> listKeys = listKeys(list);
1070         GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(packageName, list, listKeys);
1071
1072         final Set<DataSchemaNode> schemaNodes = list.getChildNodes();
1073
1074         for (final DataSchemaNode schemaNode : schemaNodes) {
1075             if (schemaNode.isAugmenting()) {
1076                 continue;
1077             }
1078             addSchemaNodeToListBuilders(basePackageName, schemaNode, typeBuilder, genTOBuilder, listKeys);
1079         }
1080         return typeBuildersToGenTypes(typeBuilder, genTOBuilder);
1081     }
1082
1083     private void addSchemaNodeToListBuilders(final String basePackageName, final DataSchemaNode schemaNode,
1084             final GeneratedTypeBuilder typeBuilder, final GeneratedTOBuilder genTOBuilder, final List<String> listKeys) {
1085         if (schemaNode == null) {
1086             throw new IllegalArgumentException("Data Schema Node cannot be NULL!");
1087         }
1088
1089         if (typeBuilder == null) {
1090             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1091         }
1092
1093         if (schemaNode instanceof LeafSchemaNode) {
1094             final LeafSchemaNode leaf = (LeafSchemaNode) schemaNode;
1095             if (!isPartOfListKey(leaf, listKeys)) {
1096                 resolveLeafSchemaNodeAsMethod(typeBuilder, leaf);
1097             } else {
1098                 resolveLeafSchemaNodeAsProperty(genTOBuilder, leaf, true);
1099             }
1100         } else if (schemaNode instanceof LeafListSchemaNode) {
1101             resolveLeafListSchemaNode(typeBuilder, (LeafListSchemaNode) schemaNode);
1102         } else if (schemaNode instanceof ContainerSchemaNode) {
1103             resolveContainerSchemaNode(basePackageName, typeBuilder, (ContainerSchemaNode) schemaNode);
1104         } else if (schemaNode instanceof ListSchemaNode) {
1105             resolveListSchemaNode(basePackageName, typeBuilder, (ListSchemaNode) schemaNode);
1106         }
1107     }
1108
1109     private List<Type> typeBuildersToGenTypes(final GeneratedTypeBuilder typeBuilder, GeneratedTOBuilder genTOBuilder) {
1110         final List<Type> genTypes = new ArrayList<>();
1111         if (typeBuilder == null) {
1112             throw new IllegalArgumentException("Generated Type Builder cannot be NULL!");
1113         }
1114
1115         if (genTOBuilder != null) {
1116             final GeneratedTransferObject genTO = genTOBuilder.toInstance();
1117             constructGetter(typeBuilder, genTO.getName(), "Returns Primary Key of Yang List Type", genTO);
1118             genTypes.add(genTO);
1119         }
1120         genTypes.add(typeBuilder.toInstance());
1121         return genTypes;
1122     }
1123
1124     /**
1125      * @param list
1126      * @return
1127      */
1128     private GeneratedTOBuilder resolveListKey(final String packageName, final ListSchemaNode list) {
1129         final String listName = list.getQName().getLocalName() + "Key";
1130         return schemaNodeToTransferObjectBuilder(packageName, list, listName);
1131     }
1132
1133     private boolean isPartOfListKey(final LeafSchemaNode leaf, final List<String> keys) {
1134         if ((leaf != null) && (keys != null) && (leaf.getQName() != null)) {
1135             final String leafName = leaf.getQName().getLocalName();
1136             if (keys.contains(leafName)) {
1137                 return true;
1138             }
1139         }
1140         return false;
1141     }
1142
1143     private List<String> listKeys(final ListSchemaNode list) {
1144         final List<String> listKeys = new ArrayList<>();
1145
1146         if (list.getKeyDefinition() != null) {
1147             final List<QName> keyDefinitions = list.getKeyDefinition();
1148
1149             for (final QName keyDefinition : keyDefinitions) {
1150                 listKeys.add(keyDefinition.getLocalName());
1151             }
1152         }
1153         return listKeys;
1154     }
1155
1156     private GeneratedTypeBuilder resolveListTypeBuilder(final String packageName, final ListSchemaNode list) {
1157         if (packageName == null) {
1158             throw new IllegalArgumentException("Package Name for Generated Type cannot be NULL!");
1159         }
1160         if (list == null) {
1161             throw new IllegalArgumentException("List Schema Node cannot be NULL!");
1162         }
1163
1164         final String schemaNodeName = list.getQName().getLocalName();
1165         final String genTypeName = parseToClassName(schemaNodeName);
1166
1167         GeneratedTypeBuilder typeBuilder = null;
1168         final Map<String, GeneratedTypeBuilder> builders = genTypeBuilders.get(packageName);
1169         if (builders != null) {
1170             typeBuilder = builders.get(genTypeName);
1171         }
1172         if (typeBuilder == null) {
1173             typeBuilder = addDefaultInterfaceDefinition(packageName, list);
1174         }
1175         return typeBuilder;
1176     }
1177
1178     private GeneratedTOBuilder resolveListKeyTOBuilder(final String packageName, final ListSchemaNode list,
1179             final List<String> listKeys) {
1180         GeneratedTOBuilder genTOBuilder = null;
1181         if (listKeys.size() > 0) {
1182             genTOBuilder = resolveListKey(packageName, list);
1183         }
1184         return genTOBuilder;
1185     }
1186
1187     
1188     private GeneratedTOBuilder addEnclosedTOToTypeBuilder( TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder, String leafName) { 
1189         String className = parseToClassName(leafName);
1190         GeneratedTOBuilder genTOBuilder = null;
1191         if (typeDef instanceof UnionType) {
1192             genTOBuilder = ((TypeProviderImpl) typeProvider).addUnionGeneratedTypeDefinition(
1193                     typeBuilder.getPackageName(), typeDef, className);
1194         } else if (typeDef instanceof BitsTypeDefinition) {
1195             genTOBuilder = ((TypeProviderImpl) typeProvider).bitsTypedefToTransferObject(
1196                     typeBuilder.getPackageName(), typeDef, className);
1197         }
1198         if (genTOBuilder != null) {
1199             typeBuilder.addEnclosingTransferObject(genTOBuilder);
1200             return genTOBuilder;
1201         }
1202         return null;
1203         
1204     }
1205     
1206 }