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