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