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