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