Comments of source code.
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / ClassTemplate.xtend
1 package org.opendaylight.yangtools.sal.java.api.generator
2
3 import java.util.List
4 import java.util.Map
5 import org.opendaylight.yangtools.binding.generator.util.TypeConstants
6 import org.opendaylight.yangtools.sal.binding.model.api.Constant
7 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
8 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
9 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
10 import org.opendaylight.yangtools.sal.binding.model.api.Type
11 import org.opendaylight.yangtools.binding.generator.util.Types
12
13 /**
14  * Template for generating JAVA class. 
15  */
16 class ClassTemplate {
17     
18     /**
19      * Generated transfer object for which class JAVA file is generated
20      */
21     val GeneratedTransferObject genTO
22     
23     /**
24      * Map of imports for this <code>genTO</code>.
25      */
26     val Map<String, String> imports
27     
28     /**
29      * List of generated property instances which represents class attributes.
30      */
31     val List<GeneratedProperty> fields
32     
33     /**
34      * List of enumeration which are generated as JAVA enum type.
35      */
36     val List<Enumeration> enums
37     
38     /**
39      * List of constant instances which are generated as JAVA public static final attributes.
40      */
41     val List<Constant> consts
42     
43     /**
44      * Creates instance of this class with concrete <code>genTO</code>.
45      * 
46      * @param genTO generated transfer object which will be transformed to JAVA class source code
47      */
48     new(GeneratedTransferObject genTO) {
49         if (genTO == null) {
50             throw new IllegalArgumentException("Generated transfer object reference cannot be NULL!")
51         }
52         
53         this.genTO = genTO
54         this.imports = GeneratorUtil.createImports(genTO)
55         this.fields = genTO.properties
56         this.enums = genTO.enumerations
57         this.consts = genTO.constantDefinitions
58     }
59     
60     /**
61      * Generates JAVA class source code (package name + class body).
62      * 
63      * @return string with JAVA class source code
64      */
65     def String generate() {
66         val body = generateBody(false)
67         val pkgAndImports = generatePkgAndImports
68         return pkgAndImports.toString + body.toString
69     }
70     
71     /**
72      * Generates JAVA class source code (class body only).
73      * 
74      * @return string with JAVA class body source code
75      */
76     def generateAsInnerClass() {
77         return generateBody(true)
78     }
79     
80     /**
81      * Template method which generates class body.
82      * 
83      * @param isInnerClass boolean value which specify if generated class is|isn't inner
84      * @return string with class source code in JAVA format
85      */
86     def private generateBody(boolean isInnerClass) '''
87         «genTO.comment.generateComment»
88         «generateClassDeclaration(isInnerClass)» {
89
90             «generateEnums»
91         
92             «generateConstants»
93         
94             «generateFields»
95         
96             «generateConstructor»
97         
98             «FOR field : fields SEPARATOR "\n"»
99                 «field.generateGetter»
100                 «IF !field.readOnly»
101                 
102                     «field.generateSetter»
103                 «ENDIF»
104             «ENDFOR»
105         
106             «generateHashCode»
107         
108             «generateEquals»
109         
110             «generateToString»
111         
112         }
113     '''
114     
115     /**
116      * Template method which generates JAVA comments.
117      * 
118      * @param string with the comment for whole JAVA class
119      * @return string with comment in JAVA format
120      */
121     def private generateComment(String comment) '''
122         «IF comment != null && !comment.empty»
123             /*
124             «comment»
125             */
126         «ENDIF»
127     '''
128     
129     /**
130      * Template method which generates JAVA class declaration.
131      * 
132      * @param isInnerClass boolean value which specify if generated class is|isn't inner
133      * @return string with class declaration in JAVA format
134      */
135     def private generateClassDeclaration(boolean isInnerClass) '''
136         public«
137         IF (isInnerClass)»«
138             " static final "»«
139         ELSEIF (genTO.abstract)»«
140             " abstract "»«
141         ELSE»«
142             " "»«
143         ENDIF»class «genTO.name»«
144         IF (genTO.extends != null)»«
145             " extends "»«genTO.extends.resolveName»«
146         ENDIF»«
147         IF (!genTO.implements.empty)»«
148             " implements "»«
149             FOR type : genTO.implements SEPARATOR ", "»«
150                 type.resolveName»«
151             ENDFOR»«
152         ENDIF
153     »'''
154     
155     /**
156      * Template method which generates JAVA enum type.
157      * 
158      * @return string with inner enum source code in JAVA format
159      */
160     def private generateEnums() '''
161         «IF !enums.empty»
162             «FOR e : enums SEPARATOR "\n"»
163                 «val enumTemplate = new EnumTemplate(e)»
164                 «enumTemplate.generateAsInnerClass»
165             «ENDFOR»
166         «ENDIF»
167     '''
168     
169     /**
170      * Template method wich generates JAVA constants.
171      * 
172      * @return string with constants in JAVA format 
173      */
174     def private generateConstants() '''
175         «IF !consts.empty»
176             «FOR c : consts»
177                 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
178                     «val cValue = c.value»
179                     «IF cValue instanceof List<?>»
180                         «val cValues = cValue as List<?>»
181                         private static final List<Pattern> «Constants.MEMBER_PATTERN_LIST» = new ArrayList<Pattern>();
182                         public static final List<String> «TypeConstants.PATTERN_CONSTANT_NAME» = Arrays.asList(«
183                         FOR v : cValues SEPARATOR ", "»«
184                             IF v instanceof String»"«
185                                 v as String»"«
186                             ENDIF»«
187                         ENDFOR»);
188                         
189                         «generateStaticInicializationBlock»
190                     «ENDIF»
191                 «ELSE»
192                     public static final «c.type.resolveName» «c.name» = «c.value»;
193                 «ENDIF»
194             «ENDFOR»
195         «ENDIF»
196     '''
197     
198     /**
199      * Template method which generates JAVA static initialization block.
200      * 
201      * @return string with static initialization block in JAVA format
202      */
203     def private generateStaticInicializationBlock() '''
204         static {
205             for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
206                 «Constants.MEMBER_PATTERN_LIST».add(Pattern.compile(regEx));
207             }
208         }
209     '''
210     
211     /**
212      * Template method which generates JAVA class attributes.
213      * 
214      * @return string with the class attributes in JAVA format
215      */
216     def private generateFields() '''
217         «IF !fields.empty»
218             «FOR f : fields»
219                 private «f.returnType.resolveName» «f.fieldName»;
220             «ENDFOR»
221         «ENDIF»
222     '''
223     
224     /**
225      * Template method which generates JAVA constructor(s).
226      * 
227      * @return string with the class constructor(s) in JAVA format
228      */
229     def private generateConstructor() '''
230         «val genTOTopParent = GeneratorUtil.getTopParrentTransportObject(genTO)»
231         «val properties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)»
232         «val propertiesAllParents = GeneratorUtil.getPropertiesOfAllParents(genTO)»
233         «IF !genTO.unionType»
234 «««            create constructor for every parent property
235             «IF genTOTopParent != genTO && genTOTopParent.unionType»
236                 «FOR parentProperty : propertiesAllParents SEPARATOR "\n"»
237                     «val parentPropertyAndProperties = properties + #[parentProperty]»
238                     «if (genTO.abstract) "protected" else "public"» «genTO.name»(«parentPropertyAndProperties.generateParameters») {
239                         super(«#[parentProperty].generateParameterNames»);
240                         «FOR property : properties»
241                             this.«property.fieldName» = «property.name»;
242                         «ENDFOR»
243                     }
244                 «ENDFOR»
245 «««            create one constructor
246             «ELSE»
247                 «val propertiesAll = propertiesAllParents + properties»
248                 «if (genTO.abstract) "protected" else "public"» «genTO.name»(«propertiesAll.generateParameters») {
249                     super(«propertiesAllParents.generateParameterNames()»);
250                     «FOR property : properties»
251                         this.«property.fieldName» = «property.fieldName»;
252                     «ENDFOR»
253                 }
254             «ENDIF»
255 «««        create constructor for every property
256         «ELSE»
257             «FOR property : properties SEPARATOR "\n"»
258                 «val propertyAndTopParentProperties = propertiesAllParents + #[property]»
259                 «if (genTO.abstract) "protected" else "public"» «genTO.name»(«propertyAndTopParentProperties.generateParameters») {
260                     super(«propertiesAllParents.generateParameterNames()»);
261                     this.«property.fieldName» = «property.fieldName»;
262                 }
263             «ENDFOR»
264         «ENDIF»
265     '''
266     
267     /**
268      * Template method which generates the getter method for <code>field</code>
269      * 
270      * @param field 
271      * generated property with data about field which is generated as the getter method
272      * @return string with the getter method source code in JAVA format 
273      */     
274     def private generateGetter(GeneratedProperty field) {
275         val prefix = if(field.returnType.equals(Types.typeForClass(Boolean))) "is" else "get"
276     '''
277         public «field.returnType.resolveName» «prefix»«field.name.toFirstUpper»() {
278             return «field.fieldName»;
279
280         }
281     '''
282     }
283     /**
284      * Template method which generates the setter method for <code>field</code>
285      * 
286      * @param field 
287      * generated property with data about field which is generated as the setter method
288      * @return string with the setter method source code in JAVA format 
289      */
290      def private generateSetter(GeneratedProperty field) '''
291         «val type = field.returnType.resolveName»
292         public void set«field.name.toFirstUpper»(«type» «field.fieldName») {
293             this.«field.fieldName» = «field.fieldName»;
294         }
295     '''
296     
297     /**
298      * Template method which generates method parameters with their types from <code>parameters</code>.
299      * 
300      * @param parameters
301      * group of generated property instances which are transformed to the method parameters
302      * @return string with the list of the method parameters with their types in JAVA format
303      */
304     def private generateParameters(Iterable<GeneratedProperty> parameters) '''«
305         IF !parameters.empty»«
306             FOR parameter : parameters SEPARATOR ", "»«
307                 parameter.returnType.resolveName» «parameter.fieldName»«
308             ENDFOR»«
309         ENDIF
310     »'''
311     
312     /**
313      * Template method which generates sequence of the names of the class attributes from <code>parameters</code>.
314      * 
315      * @param parameters 
316      * group of generated property instances which are transformed to the sequence of parameter names
317      * @return string with the list of the parameter names of the <code>parameters</code> 
318      */
319     def private generateParameterNames(Iterable<GeneratedProperty> parameters) '''«
320         IF !parameters.empty»«
321             FOR parameter : parameters SEPARATOR ", "»«
322                 parameter.fieldName»«
323             ENDFOR»«
324         ENDIF
325     »'''
326     
327     /**
328      * Template method which generates the method <code>hashCode()</code>.
329      * 
330      * @return string with the <code>hashCode()</code> method definition in JAVA format
331      */
332     def private generateHashCode() '''
333         «IF !genTO.hashCodeIdentifiers.empty»
334             @Override
335             public int hashCode() {
336                 final int prime = 31;
337                 int result = 1;
338                 «FOR property : genTO.hashCodeIdentifiers»
339                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
340                 «ENDFOR»
341                 return result;
342             }
343         «ENDIF»
344     '''
345     
346     /**
347      * Template method which generates the method <code>equals()</code>.
348      * 
349      * @return string with the <code>equals()</code> method definition in JAVA format     
350      */
351     def private generateEquals() '''
352         «IF !genTO.equalsIdentifiers.empty»
353             @Override
354             public boolean equals(java.lang.Object obj) {
355                 if (this == obj) {
356                     return true;
357                 }
358                 if (obj == null) {
359                     return false;
360                 }
361                 if (getClass() != obj.getClass()) {
362                     return false;
363                 }
364                 «genTO.name» other = («genTO.name») obj;
365                 «FOR property : genTO.equalsIdentifiers»
366                     «val fieldName = property.fieldName»
367                     if («fieldName» == null) {
368                         if (other.«fieldName» != null) {
369                             return false;
370                         }
371                     } else if(!«fieldName».equals(other.«fieldName»)) {
372                         return false;
373                     }
374                 «ENDFOR»
375                 return true;
376             }
377         «ENDIF»
378     '''
379     
380     /**
381      * Template method which generates the method <code>toString()</code>.
382      * 
383      * @return string with the <code>toString()</code> method definition in JAVA format     
384      */
385     def private generateToString() '''
386         «IF !genTO.toStringIdentifiers.empty»
387             @Override
388             public String toString() {
389                 StringBuilder builder = new StringBuilder();
390                 «val properties = genTO.toStringIdentifiers»
391                 builder.append("«genTO.name» [«properties.get(0).fieldName»=");
392                 builder.append(«properties.get(0).fieldName»);
393                 «FOR i : 1..<genTO.toStringIdentifiers.size»
394                     builder.append(", «properties.get(i).fieldName»=");
395                     builder.append(«properties.get(i).fieldName»);
396                 «ENDFOR»
397                 builder.append("]");
398                 return builder.toString();
399             }
400         «ENDIF»
401     '''
402     
403     /**
404      * Template method which generate package name line and import lines.
405      * 
406      * @result string with package and import lines in JAVA format
407      */
408     def private generatePkgAndImports() '''
409         package «genTO.packageName»;
410         
411         
412         «IF !imports.empty»
413             «FOR entry : imports.entrySet»
414                 import «entry.value».«entry.key»;
415             «ENDFOR»
416         «ENDIF»
417         
418     '''
419
420     /**
421      * Adds package to imports if it is necessary and returns necessary type name (with or without package name)
422      * 
423          * @param type JAVA <code>Type</code> 
424      * @return string with the type name (with or without package name)
425      */    
426     def private resolveName(Type type) {
427         GeneratorUtil.putTypeIntoImports(genTO, type, imports);
428         GeneratorUtil.getExplicitType(genTO, type, imports)
429     }
430     
431     def private fieldName(GeneratedProperty property) {
432         '''_«property.name»'''
433     }
434 }