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