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