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