Merge "OF plugin classes must have a strict dependency on Connection Service"
[controller.git] / opendaylight / sal / yang-prototype / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / controller / sal / java / api / generator / BuilderTemplate.xtend
1 package org.opendaylight.controller.sal.java.api.generator
2
3 import java.util.LinkedHashSet
4 import java.util.List
5 import java.util.Map
6 import java.util.Set
7 import org.opendaylight.controller.binding.generator.util.ReferencedTypeImpl
8 import org.opendaylight.controller.binding.generator.util.Types
9 import org.opendaylight.controller.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl
10 import org.opendaylight.controller.sal.binding.model.api.GeneratedProperty
11 import org.opendaylight.controller.sal.binding.model.api.GeneratedTransferObject
12 import org.opendaylight.controller.sal.binding.model.api.GeneratedType
13 import org.opendaylight.controller.sal.binding.model.api.MethodSignature
14 import org.opendaylight.controller.sal.binding.model.api.Type
15 import org.opendaylight.yangtools.yang.binding.Augmentable
16
17 class BuilderTemplate {
18
19     val static GET_PREFIX = "get"
20     val static JAVA_UTIL = "java.util"
21     val static HASH_MAP = "HashMap"
22     val static MAP = "Map"
23     val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"
24     val static BUILDER = 'Builder'
25     val static IMPL = 'Impl'
26     
27     val GeneratedType genType
28     val Map<String, String> imports
29     var GeneratedProperty augmentField
30     val Set<GeneratedProperty> fields
31     
32     new(GeneratedType genType) {
33         if (genType == null) {
34             throw new IllegalArgumentException("Generated type reference cannot be NULL!")
35         }
36         
37         this.genType = genType
38         this.imports = GeneratorUtil.createChildImports(genType)
39         this.fields = createFieldsFromMethods(createMethods)
40     }
41     
42     def private Set<MethodSignature> createMethods() {
43         val Set<MethodSignature> methods = new LinkedHashSet
44         methods.addAll(genType.methodDefinitions)
45         storeMethodsOfImplementedIfcs(methods, genType.implements)
46         return methods
47     }
48     
49     def private void storeMethodsOfImplementedIfcs(Set<MethodSignature> methods, List<Type> implementedIfcs) {
50         if (implementedIfcs == null || implementedIfcs.empty) {
51             return
52         }
53         for (implementedIfc : implementedIfcs) {
54             if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
55                 val ifc = implementedIfc as GeneratedType
56                 methods.addAll(ifc.methodDefinitions)
57                 storeMethodsOfImplementedIfcs(methods, ifc.implements)
58             } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {
59                 for (m : Augmentable.methods) {
60                     if (m.name == GET_AUGMENTATION_METHOD_NAME) {
61                         addToImports(JAVA_UTIL, HASH_MAP)
62                         addToImports(JAVA_UTIL, MAP)
63                         val fullyQualifiedName = m.returnType.name
64                         val pkg = fullyQualifiedName.package
65                         val name = fullyQualifiedName.name
66                         addToImports(pkg, name)
67                         val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)
68                         val type = new ReferencedTypeImpl(pkg, name)
69                         val generic = new ReferencedTypeImpl(genType.packageName, genType.name)
70                         val parametrizedReturnType = Types.parameterizedTypeFor(type, generic)
71                         tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)
72                         augmentField = tmpGenTO.toInstance.methodDefinitions.first.createFieldFromGetter
73                     }
74                 }
75             }
76         }
77     }
78     
79     def private void addToImports(String typePackageName,String typeName) {
80         if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
81             return
82         }
83         if (!imports.containsKey(typeName)) {
84             imports.put(typeName, typePackageName)
85         }
86     }
87     
88     def private <E> first(List<E> elements) {
89         elements.get(0)
90     }
91     
92     def private String getPackage(String fullyQualifiedName) {
93         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
94         return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)
95     }
96
97     def private String getName(String fullyQualifiedName) {
98         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
99         return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)
100     }
101     
102     def private createFieldsFromMethods(Set<MethodSignature> methods) {
103         val Set<GeneratedProperty> result = new LinkedHashSet
104
105         if (methods == null || methods.isEmpty()) {
106             return result
107         }
108
109         for (m : methods) {
110             val createdField = m.createFieldFromGetter
111             if (createdField != null) {
112                 result.add(createdField)
113             }
114         }
115         return result
116     }
117     
118     def private GeneratedProperty createFieldFromGetter(MethodSignature method) {
119         if (method == null || method.name == null || method.name.empty || method.returnType == null) {
120             throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")
121         }
122         if (method.name.startsWith(GET_PREFIX)) {
123             val fieldName = method.getName().substring(GET_PREFIX.length()).toFirstLower
124             val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")
125             tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)
126             return tmpGenTO.toInstance.properties.first
127         }
128     }
129
130     def generate() {
131         val body = generateBody
132         val pkgAndImports = generatePkgAndImports
133         return pkgAndImports.toString + body.toString
134     }
135     
136     def private generateBody() '''
137         public class «genType.name»«BUILDER» {
138         
139             «generateFields»
140
141             «generateSetters»
142
143             public «genType.name» build() {
144                 return new «genType.name»«IMPL»();
145             }
146
147             private class «genType.name»«IMPL» implements «genType.name» {
148
149                 «generateFields»
150
151                 «generateConstructor»
152
153                 «generateGetters»
154
155             }
156
157         }
158     '''
159
160     def private generateFields() '''
161         «IF !fields.empty»
162             «FOR f : fields»
163                 private «f.returnType.resolveName» «f.name»;
164             «ENDFOR»
165         «ENDIF»
166         «IF augmentField != null»
167             private Map<Class<? extends «augmentField.returnType.resolveName»>, «augmentField.returnType.resolveName»> «augmentField.name» = new HashMap<>();
168         «ENDIF»
169     '''
170
171     def private generateSetters() '''
172         «FOR field : fields SEPARATOR '\n'»
173             public «genType.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.resolveName» «field.name») {
174                 this.«field.name» = «field.name»;
175                 return this;
176             }
177         «ENDFOR»
178         «IF augmentField != null»
179             
180             public «genType.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.resolveName»> augmentationType, «augmentField.returnType.resolveName» augmentation) {
181                 this.«augmentField.name».put(augmentationType, augmentation);
182                 return this;
183             }
184         «ENDIF»
185     '''
186     
187     def private generateConstructor() '''
188         private «genType.name»«IMPL»() {
189             «IF !fields.empty»
190                 «FOR field : fields»
191                     this.«field.name» = «genType.name»«BUILDER».this.«field.name»;
192                 «ENDFOR»
193             «ENDIF»
194             «IF augmentField != null»
195                 this.«augmentField.name».putAll(«genType.name»«BUILDER».this.«augmentField.name»);
196             «ENDIF»
197         }
198     '''
199     
200     def private generateGetters() '''
201         «IF !fields.empty»
202             «FOR field : fields SEPARATOR '\n'»
203                 @Override
204                 public «field.returnType.resolveName» get«field.name.toFirstUpper»() {
205                     return «field.name»;
206                 }
207             «ENDFOR»
208         «ENDIF»
209         «IF augmentField != null»
210
211             @SuppressWarnings("unchecked")
212             @Override
213             public <E extends «augmentField.returnType.resolveName»> E get«augmentField.name.toFirstUpper»(Class<E> augmentationType) {
214                 if (augmentationType == null) {
215                     throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
216                 }
217                 return (E) «augmentField.name».get(augmentationType);
218             }
219         «ENDIF»
220     '''    
221     
222     def private generatePkgAndImports() '''
223         package «genType.packageName»;
224         
225         
226         «IF !imports.empty»
227             «FOR entry : imports.entrySet»
228                 import «entry.value».«entry.key»;
229             «ENDFOR»
230         «ENDIF»
231         
232     '''
233     
234     def private resolveName(Type type) {
235         GeneratorUtil.putTypeIntoImports(genType, type, imports);
236         GeneratorUtil.getExplicitType(genType, type, imports)
237     }
238     
239 }
240