Improved support for default yang statements in configuration subsystem
[controller.git] / opendaylight / config / yang-jmx-generator-plugin / src / main / java / org / opendaylight / controller / config / yangjmxgenerator / plugin / ftl / TemplateFactory.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.config.yangjmxgenerator.plugin.ftl;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Collections2;
13 import com.google.common.collect.Lists;
14 import com.google.common.collect.Maps;
15 import org.opendaylight.controller.config.api.RuntimeBeanRegistratorAwareModule;
16 import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
17 import org.opendaylight.controller.config.api.runtime.RuntimeBean;
18 import org.opendaylight.controller.config.spi.Module;
19 import org.opendaylight.controller.config.yangjmxgenerator.AbstractEntry;
20 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
21 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
22 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
23 import org.opendaylight.controller.config.yangjmxgenerator.ServiceInterfaceEntry;
24 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AbstractDependencyAttribute;
25 import org.opendaylight.controller.config.yangjmxgenerator.attribute.AttributeIfc;
26 import org.opendaylight.controller.config.yangjmxgenerator.attribute.Dependency;
27 import org.opendaylight.controller.config.yangjmxgenerator.attribute.JavaAttribute;
28 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribute;
29 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
30 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TypedAttribute;
31 import org.opendaylight.controller.config.yangjmxgenerator.attribute.VoidAttribute;
32 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation;
33 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Annotation.Parameter;
34 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Constructor;
35 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Field;
36 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.Header;
37 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDeclaration;
38 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.MethodDefinition;
39 import org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.model.ModuleField;
40 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.FullyQualifiedNameHelper;
41 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
42 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
43 import org.opendaylight.yangtools.sal.binding.model.api.Type;
44
45 import javax.management.openmbean.SimpleType;
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Map.Entry;
54
55 public class TemplateFactory {
56
57     public static Map<String, FtlTemplate> getFtlTemplates(
58             ModuleMXBeanEntry entry) {
59         Map<String, FtlTemplate> result = new HashMap<>();
60
61         result.putAll(TemplateFactory.tOsFromMbe(entry));
62
63         // IFC
64         result.put(entry.getMXBeanInterfaceName() + ".java",
65                 TemplateFactory.mXBeanInterfaceTemplateFromMbe(entry));
66
67         // ABS fact
68         result.put(entry.getAbstractFactoryName() + ".java",
69                 TemplateFactory.abstractFactoryTemplateFromMbe(entry));
70
71         // ABS module
72         result.put(entry.getAbstractModuleName() + ".java",
73                 TemplateFactory.abstractModuleTemplateFromMbe(entry));
74
75         return result;
76     }
77
78     public static Map<String, FtlTemplate> getFtlStubTemplates(
79             ModuleMXBeanEntry entry) {
80         Map<String, FtlTemplate> result = new HashMap<>();
81         // STUB fact
82         result.put(entry.getStubFactoryName() + ".java",
83                 TemplateFactory.stubFactoryTemplateFromMbe(entry));
84
85         result.put(entry.getStubModuleName() + ".java",
86                 TemplateFactory.stubModuleTemplateFromMbe(entry));
87         return result;
88     }
89
90     public static Map<String, FtlTemplate> getFtlTemplates(
91             ServiceInterfaceEntry entry) {
92
93         Map<String, FtlTemplate> result = new HashMap<>();
94         result.put(entry.getTypeName() + ".java",
95                 TemplateFactory.serviceInterfaceFromSie(entry));
96
97         return result;
98     }
99
100     /**
101      * Get map of file name as key, FtlFile instance representing runtime mx
102      * bean as value that should be persisted from this instance.
103      */
104     public static Map<String, FtlTemplate> getTOAndMXInterfaceFtlFiles(
105             RuntimeBeanEntry entry) {
106         Map<String, FtlTemplate> result = new HashMap<>();
107         { // create GeneralInterfaceFtlFile for runtime MXBean. Attributes will
108           // be transformed to getter methods
109             String mxBeanTypeName = entry.getJavaNameOfRuntimeMXBean();
110             List<String> extendedInterfaces = Arrays.asList(RuntimeBean.class
111                     .getCanonicalName());
112             List<MethodDeclaration> methods = new ArrayList<>();
113
114             // convert attributes to getters
115             for (AttributeIfc attributeIfc : entry.getAttributes()) {
116                 String returnType;
117                 returnType = getReturnType(attributeIfc);
118                 String getterName = "get"
119                         + attributeIfc.getUpperCaseCammelCase();
120                 MethodDeclaration getter = new MethodDeclaration(returnType,
121                         getterName, Collections.<Field> emptyList());
122                 methods.add(getter);
123             }
124
125             // add rpc methods
126             for (Rpc rpc : entry.getRpcs()) {
127                 // convert JavaAttribute parameters into fields
128                 List<Field> fields = new ArrayList<>();
129                 for (JavaAttribute ja : rpc.getParameters()) {
130                     Field field = new Field(Collections.<String> emptyList(),
131                             ja.getType().getFullyQualifiedName(),
132                             ja.getLowerCaseCammelCase(), ja.getNullableDefaultWrappedForCode());
133                     fields.add(field);
134                 }
135                 MethodDeclaration operation = new MethodDeclaration(
136                         getReturnType(rpc.getReturnType()), rpc.getName(), fields);
137                 methods.add(operation);
138             }
139
140             // FIXME header
141             GeneralInterfaceTemplate runtimeMxBeanIfc = new GeneralInterfaceTemplate(
142                     null, entry.getPackageName(), mxBeanTypeName,
143                     extendedInterfaces, methods);
144
145             result.put(runtimeMxBeanIfc.getTypeDeclaration().getName()
146                     + ".java", runtimeMxBeanIfc);
147         }
148
149         result.putAll(TemplateFactory.tOsFromRbe(entry));
150
151         return result;
152     }
153
154     // FIXME: put into Type.toString
155     static String serializeType(Type type) {
156         if (type instanceof ParameterizedType){
157             ParameterizedType parameterizedType = (ParameterizedType) type;
158             StringBuffer sb = new StringBuffer();
159             sb.append(parameterizedType.getRawType().getFullyQualifiedName());
160             sb.append("<");
161             boolean first = true;
162             for(Type parameter: parameterizedType.getActualTypeArguments()) {
163                 if (first) {
164                     first = false;
165                 } else {
166                     sb.append(",");
167                 }
168                 sb.append(serializeType(parameter));
169             }
170             sb.append(">");
171             return sb.toString();
172         } else {
173             return type.getFullyQualifiedName();
174         }
175     }
176
177
178     private static String getReturnType(AttributeIfc attributeIfc) {
179         String returnType;
180         if (attributeIfc instanceof TypedAttribute) {
181             Type type = ((TypedAttribute) attributeIfc).getType();
182             returnType = serializeType(type);
183         } else if (attributeIfc == VoidAttribute.getInstance()) {
184             return "void";
185         } else {
186             throw new UnsupportedOperationException(
187                     "Attribute not supported: "
188                             + attributeIfc.getClass());
189         }
190         return returnType;
191     }
192
193     public static GeneralInterfaceTemplate serviceInterfaceFromSie(
194             ServiceInterfaceEntry sie) {
195
196         List<String> extendedInterfaces = Lists
197                 .newArrayList(AbstractServiceInterface.class.getCanonicalName());
198         if (sie.getBase().isPresent()) {
199             extendedInterfaces.add(sie.getBase().get().getFullyQualifiedName());
200         }
201
202         // FIXME header
203         GeneralInterfaceTemplate sieTemplate = new GeneralInterfaceTemplate(
204                 getHeaderFromEntry(sie), sie.getPackageName(),
205                 sie.getTypeName(), extendedInterfaces,
206                 Lists.<MethodDeclaration> newArrayList());
207         sieTemplate.setJavadoc(sie.getNullableDescription());
208
209         if (sie.getNullableDescription() != null)
210             sieTemplate.getAnnotations().add(
211                     Annotation.createDescriptionAnnotation(sie
212                             .getNullableDescription()));
213         sieTemplate.getAnnotations().add(Annotation.createSieAnnotation(sie.getQName(), sie.getExportedOsgiClassName
214                 ()));
215
216         return sieTemplate;
217     }
218
219     public static AbstractFactoryTemplate abstractFactoryTemplateFromMbe(
220             ModuleMXBeanEntry mbe) {
221         AbstractFactoryAttributesProcessor attrProcessor = new AbstractFactoryAttributesProcessor();
222         attrProcessor.processAttributes(mbe.getAttributes(),
223                 mbe.getPackageName());
224
225         Collection<String> transformed = Collections2.transform(mbe
226                 .getProvidedServices().keySet(),
227                 new Function<String, String>() {
228
229                     @Override
230                     public String apply(String input) {
231                         return input + ".class";
232                     }
233                 });
234
235         return new AbstractFactoryTemplate(getHeaderFromEntry(mbe),
236                 mbe.getPackageName(), mbe.getAbstractFactoryName(),
237                 mbe.getGloballyUniqueName(), mbe.getFullyQualifiedName(mbe
238                         .getStubModuleName()), attrProcessor.getFields(),
239                 Lists.newArrayList(transformed));
240     }
241
242     public static AbstractModuleTemplate abstractModuleTemplateFromMbe(
243             ModuleMXBeanEntry mbe) {
244         AbstractModuleAttributesProcessor attrProcessor = new AbstractModuleAttributesProcessor();
245         attrProcessor.processAttributes(mbe.getAttributes(),
246                 mbe.getPackageName());
247
248         List<ModuleField> moduleFields = attrProcessor.getModuleFields();
249         List<String> implementedIfcs = Lists.newArrayList(
250                 Module.class.getCanonicalName(),
251                 mbe.getFullyQualifiedName(mbe.getMXBeanInterfaceName()));
252
253         for (String implementedService : mbe.getProvidedServices().keySet()) {
254             implementedIfcs.add(implementedService);
255         }
256
257         boolean generateRuntime = false;
258         String registratorFullyQualifiedName = null;
259         if (mbe.getRuntimeBeans() != null
260                 && mbe.getRuntimeBeans().isEmpty() == false) {
261             generateRuntime = true;
262             RuntimeBeanEntry rootEntry = RuntimeRegistratorFtlTemplate
263                     .findRoot(mbe.getRuntimeBeans());
264             registratorFullyQualifiedName = rootEntry
265                     .getPackageName()
266                     .concat(".")
267                     .concat(RuntimeRegistratorFtlTemplate.getJavaNameOfRuntimeRegistrator(rootEntry));
268             implementedIfcs.add(RuntimeBeanRegistratorAwareModule.class
269                     .getCanonicalName());
270         }
271
272         AbstractModuleTemplate abstractModuleTemplate = new AbstractModuleTemplate(
273                 getHeaderFromEntry(mbe), mbe.getPackageName(),
274                 mbe.getAbstractModuleName(), implementedIfcs, moduleFields,
275                 attrProcessor.getMethods(), generateRuntime,
276                 registratorFullyQualifiedName);
277
278         if (mbe.getNullableDescription() != null)
279             abstractModuleTemplate.getAnnotations().add(
280                     Annotation.createDescriptionAnnotation(mbe
281                             .getNullableDescription()));
282         return abstractModuleTemplate;
283     }
284
285     public static StubFactoryTemplate stubFactoryTemplateFromMbe(
286             ModuleMXBeanEntry mbe) {
287         return new StubFactoryTemplate(getHeaderFromEntry(mbe),
288                 mbe.getPackageName(), mbe.getStubFactoryName(),
289                 mbe.getFullyQualifiedName(mbe.getAbstractFactoryName()),
290                 mbe.getStubModuleName());
291     }
292
293     public static StubModuleTemplate stubModuleTemplateFromMbe(
294             ModuleMXBeanEntry mbe) {
295         return new StubModuleTemplate(getHeaderFromEntry(mbe),
296                 mbe.getPackageName(), mbe.getStubModuleName(),
297                 mbe.getFullyQualifiedName(mbe.getAbstractModuleName()));
298     }
299
300     public static GeneralInterfaceTemplate mXBeanInterfaceTemplateFromMbe(
301             ModuleMXBeanEntry mbe) {
302         MXBeanInterfaceAttributesProcessor attrProcessor = new MXBeanInterfaceAttributesProcessor();
303         attrProcessor.processAttributes(mbe.getAttributes());
304         GeneralInterfaceTemplate ifcTemplate = new GeneralInterfaceTemplate(
305                 getHeaderFromEntry(mbe), mbe.getPackageName(),
306                 mbe.getMXBeanInterfaceName(), Lists.<String> newArrayList(),
307                 attrProcessor.getMethods());
308         ifcTemplate.setJavadoc(mbe.getNullableDescription());
309         return ifcTemplate;
310     }
311
312     public static Map<String, GeneralClassTemplate> tOsFromMbe(
313             ModuleMXBeanEntry mbe) {
314         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
315         TOAttributesProcessor processor = new TOAttributesProcessor();
316         processor.processAttributes(mbe.getAttributes());
317         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
318                 .getTOs()) {
319             List<Constructor> constructors = Lists.newArrayList();
320             constructors.add(new Constructor(to.getName(), "super();"));
321
322             Header header = getHeaderFromEntry(mbe);
323             retVal.put(
324                     to.getType(),
325                     new GeneralClassTemplate(header, mbe.getPackageName(), to
326                             .getName(), Collections.<String> emptyList(),
327                             Collections.<String> emptyList(), to.getFields(),
328                             to.getMethods(), false, false, constructors));
329         }
330         return retVal;
331     }
332
333     public static Map<String, GeneralClassTemplate> tOsFromRbe(
334             RuntimeBeanEntry rbe) {
335         Map<String, GeneralClassTemplate> retVal = Maps.newHashMap();
336         TOAttributesProcessor processor = new TOAttributesProcessor();
337         Map<String, AttributeIfc> yangPropertiesToTypesMap = Maps.newHashMap(rbe.getYangPropertiesToTypesMap());
338
339         // Add TOs from output parameters
340         for (Rpc rpc : rbe.getRpcs()) {
341             AttributeIfc returnType = rpc.getReturnType();
342
343             if (returnType == VoidAttribute.getInstance())
344                 continue;
345             if (returnType instanceof JavaAttribute)
346                 continue;
347             if (returnType instanceof ListAttribute && returnType.getOpenType() instanceof SimpleType)
348                 continue;
349
350             Preconditions.checkState(yangPropertiesToTypesMap.containsKey(returnType.getAttributeYangName()) == false,
351                     "Duplicate TO %s for %s", returnType.getAttributeYangName(), rbe);
352             yangPropertiesToTypesMap.put(returnType.getAttributeYangName(), returnType);
353         }
354
355         processor.processAttributes(yangPropertiesToTypesMap);
356         for (org.opendaylight.controller.config.yangjmxgenerator.plugin.ftl.TemplateFactory.TOAttributesProcessor.TOInternal to : processor
357                 .getTOs()) {
358             List<Constructor> constructors = Lists.newArrayList();
359             constructors.add(new Constructor(to.getName(), "super();"));
360
361             // TODO header
362             retVal.put(
363                     to.getType(),
364                     new GeneralClassTemplate(null, rbe.getPackageName(), to
365                             .getName(), Collections.<String> emptyList(),
366                             Collections.<String> emptyList(), to.getFields(),
367                             to.getMethods(), false, false, constructors));
368         }
369         return retVal;
370     }
371
372     private static Header getHeaderFromEntry(AbstractEntry mbe) {
373         return new Header(mbe.getYangModuleName(), mbe.getYangModuleLocalname());
374     }
375
376     // TODO refactor attribute processors
377
378     private static class TOAttributesProcessor {
379
380         private final List<TOInternal> tos = Lists.newArrayList();
381
382         void processAttributes(Map<String, AttributeIfc> attributes) {
383             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
384                 AttributeIfc attributeIfc = attrEntry.getValue();
385                 if (attributeIfc instanceof TOAttribute) {
386                     createTOInternal((TOAttribute) attributeIfc);
387                 }
388                 if (attributeIfc instanceof ListAttribute) {
389                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
390                             .getInnerAttribute();
391                     if (innerAttr instanceof TOAttribute) {
392                         createTOInternal((TOAttribute) innerAttr);
393                     }
394                 }
395             }
396         }
397
398         private void createTOInternal(TOAttribute toAttribute) {
399
400             Map<String, AttributeIfc> attrs = toAttribute.getCapitalizedPropertiesToTypesMap();
401             // recursive processing of TO's attributes
402             processAttributes(attrs);
403
404             tos.add(new TOInternal(toAttribute.getType(), attrs));
405         }
406
407         List<TOInternal> getTOs() {
408             return tos;
409         }
410
411         private static class TOInternal {
412             private final String fullyQualifiedName, name;
413             private List<Field> fields;
414             private List<MethodDefinition> methods;
415
416             public TOInternal(Type type, Map<String, AttributeIfc> attrs) {
417                 this(type.getFullyQualifiedName(), type.getName(), attrs, type.getPackageName());
418             }
419
420             public TOInternal(String fullyQualifiedName, String name,
421                     Map<String, AttributeIfc> attrs, String packageName) {
422                 this.fullyQualifiedName = fullyQualifiedName;
423                 this.name = name;
424                 processAttrs(attrs, packageName);
425             }
426
427             private void processAttrs(Map<String, AttributeIfc> attrs, String packageName) {
428                 fields = Lists.newArrayList();
429                 methods = Lists.newArrayList();
430
431                 for (Entry<String, AttributeIfc> attrEntry : attrs.entrySet()) {
432                     String innerName = attrEntry.getKey();
433                     String varName = BindingGeneratorUtil
434                             .parseToValidParamName(attrEntry.getKey());
435
436                     String fullyQualifiedName, nullableDefault = null;
437                     if (attrEntry.getValue() instanceof TypedAttribute) {
438                         Type type = ((TypedAttribute) attrEntry.getValue()).getType();
439                         fullyQualifiedName = serializeType(type);
440                         if(attrEntry.getValue() instanceof JavaAttribute) {
441                             nullableDefault = ((JavaAttribute)attrEntry.getValue()).getNullableDefaultWrappedForCode();
442                         }
443                     } else {
444                         fullyQualifiedName = FullyQualifiedNameHelper
445                                 .getFullyQualifiedName(packageName, attrEntry.getValue().getUpperCaseCammelCase());
446                     }
447                     fields.add(new Field(fullyQualifiedName, varName, nullableDefault));
448
449                     String getterName = "get" + innerName;
450                     MethodDefinition getter = new MethodDefinition(
451                             fullyQualifiedName, getterName,
452                             Collections.<Field> emptyList(), "return "
453                                     + varName + ";");
454
455                     String setterName = "set" + innerName;
456                     MethodDefinition setter = new MethodDefinition("void",
457                             setterName, Lists.newArrayList(new Field(
458                                     fullyQualifiedName, varName)), "this."
459                                     + varName + " = " + varName + ";");
460                     methods.add(getter);
461                     methods.add(setter);
462                 }
463
464             }
465
466             String getType() {
467                 return fullyQualifiedName;
468             }
469
470             String getName() {
471                 return name;
472             }
473
474             List<Field> getFields() {
475                 return fields;
476             }
477
478             List<MethodDefinition> getMethods() {
479                 return methods;
480             }
481         }
482     }
483
484     private static class MXBeanInterfaceAttributesProcessor {
485         private final List<MethodDeclaration> methods = Lists.newArrayList();
486
487         void processAttributes(Map<String, AttributeIfc> attributes) {
488             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
489                 String returnType;
490                 AttributeIfc attributeIfc = attrEntry.getValue();
491
492                 if (attributeIfc instanceof TypedAttribute) {
493                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
494                     returnType = serializeType(typedAttribute.getType());
495                 } else {
496                     throw new UnsupportedOperationException(
497                             "Attribute not supported: "
498                                     + attributeIfc.getClass());
499                 }
500
501                 String getterName = "get"
502                         + attributeIfc.getUpperCaseCammelCase();
503                 MethodDeclaration getter = new MethodDeclaration(returnType,
504                         getterName, Collections.<Field> emptyList());
505
506                 String varName = BindingGeneratorUtil
507                         .parseToValidParamName(attrEntry.getKey());
508                 String setterName = "set"
509                         + attributeIfc.getUpperCaseCammelCase();
510                 MethodDeclaration setter = new MethodDeclaration("void",
511                         setterName, Lists.newArrayList(new Field(returnType,
512                                 varName)));
513                 methods.add(getter);
514                 methods.add(setter);
515
516                 if (attributeIfc.getNullableDescription() != null) {
517                     setter.setJavadoc(attrEntry.getValue()
518                             .getNullableDescription());
519                 }
520             }
521         }
522
523         List<MethodDeclaration> getMethods() {
524             return methods;
525         }
526     }
527
528     private static class AbstractFactoryAttributesProcessor {
529
530         private final List<Field> fields = Lists.newArrayList();
531         private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
532
533         void processAttributes(Map<String, AttributeIfc> attributes,
534                 String packageName) {
535             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
536                 String type;
537                 String nullableDefaultWrapped = null;
538                 AttributeIfc attributeIfc = attrEntry.getValue();
539
540                 if (attributeIfc instanceof TypedAttribute) {
541                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
542                     type = serializeType(typedAttribute.getType());
543                 } else if (attributeIfc instanceof TOAttribute) {
544                     String fullyQualifiedName = FullyQualifiedNameHelper
545                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
546
547                     type = fullyQualifiedName;
548                 } else if (attributeIfc instanceof ListAttribute) {  //FIXME: listAttribute might extend TypedAttribute
549                     String fullyQualifiedName = null;
550                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
551                             .getInnerAttribute();
552                     if (innerAttr instanceof JavaAttribute) {
553                         fullyQualifiedName = ((JavaAttribute) innerAttr)
554                                 .getType().getFullyQualifiedName();
555                         nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
556                     } else if (innerAttr instanceof TOAttribute) {
557                         fullyQualifiedName = FullyQualifiedNameHelper
558                                 .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
559                     }
560
561                     type = STRING_FULLY_QUALIFIED_NAME.concat("<")
562                             .concat(fullyQualifiedName).concat(">");
563
564                 } else {
565                     throw new UnsupportedOperationException(
566                             "Attribute not supported: "
567                                     + attributeIfc.getClass());
568                 }
569
570                 fields.add(new Field(type, attributeIfc
571                         .getUpperCaseCammelCase(), nullableDefaultWrapped));
572             }
573         }
574
575         List<Field> getFields() {
576             return fields;
577         }
578     }
579
580     private static class AbstractModuleAttributesProcessor {
581
582         private static final String STRING_FULLY_QUALIFIED_NAME = "java.util.List";
583
584         private final List<ModuleField> moduleFields = Lists.newArrayList();
585         private final List<MethodDefinition> methods = Lists.newArrayList();
586
587         void processAttributes(Map<String, AttributeIfc> attributes,
588                 String packageName) {
589             for (Entry<String, AttributeIfc> attrEntry : attributes.entrySet()) {
590                 String type, nullableDefaultWrapped = null;
591                 AttributeIfc attributeIfc = attrEntry.getValue();
592
593                 if (attributeIfc instanceof TypedAttribute) {
594                     TypedAttribute typedAttribute = (TypedAttribute) attributeIfc;
595                     type = serializeType(typedAttribute.getType());
596                     if (attributeIfc instanceof JavaAttribute) {
597                         nullableDefaultWrapped = ((JavaAttribute) attributeIfc).getNullableDefaultWrappedForCode();
598                     }
599
600                 } else if (attributeIfc instanceof TOAttribute) {
601                     String fullyQualifiedName = FullyQualifiedNameHelper
602                             .getFullyQualifiedName(packageName, attributeIfc.getUpperCaseCammelCase());
603
604                     type = fullyQualifiedName;
605                 } else if (attributeIfc instanceof ListAttribute) {
606                     String fullyQualifiedName = null;
607                     AttributeIfc innerAttr = ((ListAttribute) attributeIfc)
608                             .getInnerAttribute();
609                     if (innerAttr instanceof JavaAttribute) {
610                         fullyQualifiedName = ((JavaAttribute) innerAttr)
611                                 .getType().getFullyQualifiedName();
612                         nullableDefaultWrapped = ((JavaAttribute) innerAttr).getNullableDefaultWrappedForCode();
613                     } else if (innerAttr instanceof TOAttribute) {
614                         fullyQualifiedName = FullyQualifiedNameHelper
615                                 .getFullyQualifiedName(packageName, innerAttr.getUpperCaseCammelCase());
616                     }
617
618                     type = STRING_FULLY_QUALIFIED_NAME.concat("<")
619                             .concat(fullyQualifiedName).concat(">");
620                 } else {
621                     throw new UnsupportedOperationException(
622                             "Attribute not supported: "
623                                     + attributeIfc.getClass());
624                 }
625
626                 boolean isDependency = false;
627                 Dependency dependency = null;
628                 Annotation overrideAnnotation = new Annotation("Override",
629                         Collections.<Parameter> emptyList());
630                 List<Annotation> annotations = Lists
631                         .newArrayList(overrideAnnotation);
632
633                 if (attributeIfc instanceof AbstractDependencyAttribute) {
634                     isDependency = true;
635                     dependency = ((AbstractDependencyAttribute) attributeIfc)
636                             .getDependency();
637                     annotations.add(Annotation
638                             .createRequireIfcAnnotation(dependency.getSie()));
639                 }
640
641                 String varName = BindingGeneratorUtil
642                         .parseToValidParamName(attrEntry.getKey());
643                 moduleFields.add(new ModuleField(type, varName, attributeIfc
644                         .getUpperCaseCammelCase(), nullableDefaultWrapped, isDependency, dependency));
645
646                 String getterName = "get"
647                         + attributeIfc.getUpperCaseCammelCase();
648                 MethodDefinition getter = new MethodDefinition(type,
649                         getterName, Collections.<Field> emptyList(),
650                         Lists.newArrayList(overrideAnnotation), "return "
651                                 + varName + ";");
652
653                 String setterName = "set"
654                         + attributeIfc.getUpperCaseCammelCase();
655
656                 if (attributeIfc.getNullableDescription() != null) {
657                     annotations.add(Annotation
658                             .createDescriptionAnnotation(attributeIfc.getNullableDescription()));
659                 }
660
661                 MethodDefinition setter = new MethodDefinition("void",
662                         setterName,
663                         Lists.newArrayList(new Field(type, varName)),
664                         annotations, "this." + varName + " = " + varName + ";");
665                 setter.setJavadoc(attributeIfc.getNullableDescription());
666
667                 methods.add(getter);
668                 methods.add(setter);
669             }
670         }
671
672         List<ModuleField> getModuleFields() {
673             return moduleFields;
674         }
675
676         List<MethodDefinition> getMethods() {
677             return methods;
678         }
679
680     }
681
682 }