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