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