Add missing copyright headers
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / ClassTemplate.xtend
1 /*
2  * Copyright (c) 2014 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.yangtools.sal.java.api.generator\r
9 \r
10 import java.util.List\r
11 import org.opendaylight.yangtools.binding.generator.util.TypeConstants\r
12 import org.opendaylight.yangtools.sal.binding.model.api.Constant\r
13 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration\r
14 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty\r
15 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject\r
16 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType\r
17 import java.util.ArrayList\r
18 import java.util.Collections\rimport java.util.Arrays
19 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
20 import com.google.common.collect.Range
21 import java.util.regex.Pattern
22 import com.google.common.io.BaseEncoding
23 import java.beans.ConstructorProperties
24 import com.google.common.collect.Lists
25
26 /**\r
27  * Template for generating JAVA class. \r
28  */\r
29 class ClassTemplate extends BaseTemplate {\r
30 \r
31     protected val List<GeneratedProperty> properties\r
32     protected val List<GeneratedProperty> finalProperties\r
33     protected val List<GeneratedProperty> parentProperties\r
34     protected val Iterable<GeneratedProperty> allProperties;\r
35     protected val Restrictions restrictions\r
36     \r
37     /**\r
38      * List of enumeration which are generated as JAVA enum type.\r
39      */\r
40     protected val List<Enumeration> enums\r
41     \r
42     /**\r
43      * List of constant instances which are generated as JAVA public static final attributes.\r
44      */\r
45     protected val List<Constant> consts\r
46     \r
47     /**\r
48      * List of generated types which are enclosed inside <code>genType</code>\r
49      */\r
50     protected val List<GeneratedType> enclosedGeneratedTypes;\r
51     \r
52     \r
53     protected val GeneratedTransferObject genTO;\r
54 \r
55     /**\r
56      * Creates instance of this class with concrete <code>genType</code>.\r
57      * \r
58      * @param genType generated transfer object which will be transformed to JAVA class source code\r
59      */\r
60     new(GeneratedTransferObject genType) {\r
61         super(genType)\r
62         this.genTO = genType\r
63         this.properties = genType.properties\r
64         this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)\r
65         this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)\r
66         this.restrictions = genType.restrictions\r
67 \r
68         var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();\r
69         sorted.addAll(properties);\r
70         sorted.addAll(parentProperties);\r
71         Collections.sort(sorted, new PropertyComparator());\r
72 \r
73         this.allProperties = sorted\r
74         this.enums = genType.enumerations\r
75         this.consts = genType.constantDefinitions\r
76         this.enclosedGeneratedTypes = genType.enclosedTypes\r
77     }\r
78 \r
79 \r
80     /**\r
81      * Generates JAVA class source code (class body only).\r
82      * \r
83      * @return string with JAVA class body source code\r
84      */\r
85     def CharSequence generateAsInnerClass() {\r
86         return generateBody(true)\r
87     }\r
88 \r
89 \r
90     override protected body() {\r
91         generateBody(false);\r
92     }\r
93 \r
94     /**\r
95      * Template method which generates class body.\r
96      * \r
97      * @param isInnerClass boolean value which specify if generated class is|isn't inner\r
98      * @return string with class source code in JAVA format\r
99      */\r
100     def protected generateBody(boolean isInnerClass) '''\r
101         «type.comment.asJavadoc»\r
102         «generateClassDeclaration(isInnerClass)» {\r
103             «suidDeclaration»\r
104             «innerClassesDeclarations»\r
105             «enumDeclarations»\r
106             «constantsDeclarations»\r
107             «generateFields»\r
108 \r
109             «constructors»\r
110             \r
111             «defaultInstance»\r
112 \r
113             «FOR field : properties SEPARATOR "\n"»\r
114                 «field.getterMethod»\r
115                 «IF !field.readOnly»\r
116                     «field.setterMethod»\r
117                 «ENDIF»\r
118             «ENDFOR»\r
119 \r
120             «generateHashCode»\r
121 \r
122             «generateEquals»\r
123 \r
124             «generateToString(genTO.toStringIdentifiers)»\r
125 \r
126             «generateGetLength»\r
127 \r
128         }\r
129     '''\r
130 \r
131 \r
132     /**\r
133      * Template method which generates inner classes inside this interface.\r
134      * \r
135      * @return string with the source code for inner classes in JAVA format\r
136      */\r
137     def protected innerClassesDeclarations() '''\r
138         «IF !enclosedGeneratedTypes.empty»\r
139             «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»\r
140                 «IF (innerClass instanceof GeneratedTransferObject)»\r
141                     «val classTemplate = new ClassTemplate(innerClass as GeneratedTransferObject)»\r
142                     «classTemplate.generateAsInnerClass»\r
143                     \r
144                 «ENDIF»\r
145             «ENDFOR»\r
146         «ENDIF»\r
147     '''\r
148     \r
149     \r
150     def protected constructors() '''\r
151         «IF genTO.unionType»\r
152             «genUnionConstructor»\r
153         «ELSE»\r
154             «allValuesConstructor»\r
155         «ENDIF»\r
156         «IF !allProperties.empty»\r
157             «copyConstructor»\r
158         «ENDIF»\r
159         «IF properties.empty && !parentProperties.empty »\r
160             «parentConstructor»\r
161         «ENDIF»\r
162     '''\r
163     \r
164     def protected allValuesConstructor() '''\r
165     «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»\r
166         @«ConstructorProperties.importedName»("value")\r
167     «ENDIF»\r
168     public «type.name»(«allProperties.asArgumentsDeclaration») {\r
169         «IF false == parentProperties.empty»\r
170             super(«parentProperties.asArguments»);\r
171         «ENDIF»\r
172         «FOR p : allProperties» \r
173             «generateRestrictions(type, p.fieldName.toString, p.returnType)»\r
174         «ENDFOR»\r
175         «FOR p : properties» \r
176             this.«p.fieldName» = «p.fieldName»;\r
177         «ENDFOR»\r
178     }\r
179     '''\r
180 \r
181     def protected genUnionConstructor() '''\r
182     «FOR p : allProperties»\r
183         «val List<GeneratedProperty> other = new ArrayList(properties)»\r
184         «val added = other.remove(p)»\r
185         «genConstructor(p, other)»\r
186     «ENDFOR»\r
187 \r
188     '''\r
189 \r
190     def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''\r
191     public «type.name»(«property.returnType.importedName + " " + property.name») {\r
192         «IF false == parentProperties.empty»\r
193             super(«parentProperties.asArguments»);\r
194         «ENDIF»\r
195             «generateRestrictions(type, property.fieldName.toString, property.returnType)»\r
196             this.«property.fieldName» = «property.name»;\r
197             «FOR p : other»\r
198             this.«p.fieldName» = null;\r
199             «ENDFOR»\r
200     }\r
201     '''\r
202 \r
203     def protected copyConstructor() '''\r
204     /**\r
205      * Creates a copy from Source Object.\r
206      *\r
207      * @param source Source object\r
208      */\r
209     public «type.name»(«type.name» source) {\r
210         «IF false == parentProperties.empty»\r
211             super(source);\r
212         «ENDIF»\r
213         «FOR p : properties» \r
214             this.«p.fieldName» = source.«p.fieldName»;\r
215         «ENDFOR»\r
216     }\r
217     '''\r
218 \r
219     def protected parentConstructor() '''\r
220     /**\r
221      * Creates a new instance from «genTO.superType.importedName»\r
222      *\r
223      * @param source Source object\r
224      */\r
225     public «type.name»(«genTO.superType.importedName» source) {\r
226             super(source);\r
227     }\r
228     '''\r
229 \r
230     def protected defaultInstance() '''\r
231         «IF genTO.typedef && !allProperties.empty && !genTO.unionType»\r
232             «val prop = allProperties.get(0)»\r
233             «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))»\r
234             public static «genTO.name» getDefaultInstance(String defaultValue) {\r
235                 «IF "byte[]".equals(prop.returnType.name)»\r
236                     «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64(); \r
237                     return new «genTO.name»(baseEncoding.decode(defaultValue));\r
238                 «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)»\r
239                     return new «genTO.name»(defaultValue);\r
240                 «ELSEIF allProperties.size > 1»\r
241                     «bitsArgs»\r
242                 «ELSE»\r
243                     return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));\r
244                 «ENDIF»\r
245             }\r
246             «ENDIF»\r
247         «ENDIF»\r
248     '''\r
249 \r
250     def protected bitsArgs() '''\r
251         «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);\r
252         if (!properties.contains(defaultValue)) {\r
253             throw new «IllegalArgumentException.importedName»("invalid default parameter");\r
254         }\r
255         int i = 0;\r
256         return new «genTO.name»(\r
257         «FOR prop : allProperties SEPARATOR ","»\r
258             properties.get(i++).equals(defaultValue) ? new «Boolean.importedName»("true") : null\r
259         «ENDFOR»\r
260         );\r
261     '''\r
262 \r
263     def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''\r
264         «FOR prop : properties SEPARATOR ","»\r
265             "«prop.name»"\r
266         «ENDFOR»\r
267     '''\r
268 \r
269     /**\r
270      * Template method which generates JAVA class declaration.\r
271      * \r
272      * @param isInnerClass boolean value which specify if generated class is|isn't inner\r
273      * @return string with class declaration in JAVA format\r
274      */\r
275     def protected generateClassDeclaration(boolean isInnerClass) '''\r
276         public«\r
277         IF (isInnerClass)»«\r
278             " static final "»«\r
279         ELSEIF (type.abstract)»«\r
280             " abstract "»«\r
281         ELSE»«\r
282             " "»«\r
283         ENDIF»class «type.name»«\r
284         IF (genTO.superType != null)»«\r
285             " extends "»«genTO.superType.importedName»«\r
286         ENDIF»\r
287         «IF (!type.implements.empty)»«\r
288             " implements "»«\r
289             FOR type : type.implements SEPARATOR ", "»«\r
290                 type.importedName»«\r
291             ENDFOR»«\r
292         ENDIF\r
293     »'''\r
294     \r
295     /**\r
296      * Template method which generates JAVA enum type.\r
297      * \r
298      * @return string with inner enum source code in JAVA format\r
299      */\r
300     def protected enumDeclarations() '''\r
301         «IF !enums.empty»\r
302             «FOR e : enums SEPARATOR "\n"»\r
303                 «val enumTemplate = new EnumTemplate(e)»\r
304                 «enumTemplate.generateAsInnerClass»\r
305             «ENDFOR»\r
306         «ENDIF»\r
307     '''\r
308 \r
309     def protected suidDeclaration() '''\r
310         «IF genTO.SUID != null»\r
311             private static final long serialVersionUID = «genTO.SUID.value»L; \r
312         «ENDIF»\r
313     '''\r
314 \r
315     /**\r
316      * Template method wich generates JAVA constants.\r
317      * \r
318      * @return string with constants in JAVA format \r
319      */\r
320     def protected constantsDeclarations() '''\r
321         «IF !consts.empty»\r
322             «FOR c : consts»\r
323                 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»\r
324                     «val cValue = c.value»\r
325                     «IF cValue instanceof List<?>»\r
326                         «val cValues = cValue as List<?>»\r
327                         private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST» = new «ArrayList.importedName»<«Pattern.importedName»>();\r
328                         public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(«\r
329                         FOR v : cValues SEPARATOR ", "»«\r
330                             IF v instanceof String»"«\r
331                                 v as String»"«\r
332                             ENDIF»«\r
333                         ENDFOR»);\r
334 \r
335                         «generateStaticInicializationBlock»\r
336                     «ENDIF»\r
337                 «ELSE»\r
338                     public static final «c.type.importedName» «c.name» = «c.value»;\r
339                 «ENDIF»\r
340             «ENDFOR»\r
341         «ENDIF»\r
342     '''\r
343 \r
344     /**\r
345      * Template method which generates JAVA static initialization block.\r
346      *\r
347      * @return string with static initialization block in JAVA format\r
348      */\r
349     def protected generateStaticInicializationBlock() '''\r
350         static {\r
351             for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {\r
352                 «Constants.MEMBER_PATTERN_LIST».add(Pattern.compile(regEx));\r
353             }\r
354         }\r
355     '''\r
356 \r
357     /**\r
358      * Template method which generates JAVA class attributes.\r
359      *\r
360      * @return string with the class attributes in JAVA format\r
361      */\r
362     def protected generateFields() '''\r
363         «IF !properties.empty»\r
364             «FOR f : properties»\r
365                 «IF f.readOnly»final«ENDIF» private «f.returnType.importedName» «f.fieldName»;\r
366             «ENDFOR»\r
367         «ENDIF»\r
368     '''\r
369 \r
370 \r
371     /**\r
372      * Template method which generates the method <code>hashCode()</code>.\r
373      *\r
374      * @return string with the <code>hashCode()</code> method definition in JAVA format\r
375      */\r
376     def protected generateHashCode() '''\r
377         «IF !genTO.hashCodeIdentifiers.empty»\r
378             @Override\r
379             public int hashCode() {\r
380                 final int prime = 31;\r
381                 int result = 1;\r
382                 «FOR property : genTO.hashCodeIdentifiers»\r
383                     «IF property.returnType.name.contains("[")»\r
384                     result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));\r
385                     «ELSE»\r
386                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
387                     «ENDIF»\r
388                 «ENDFOR»\r
389                 return result;\r
390             }\r
391         «ENDIF»\r
392     '''\r
393 \r
394     /**\r
395      * Template method which generates the method <code>equals()</code>.\r
396      *\r
397      * @return string with the <code>equals()</code> method definition in JAVA format\r
398      */\r
399     def protected generateEquals() '''\r
400         «IF !genTO.equalsIdentifiers.empty»\r
401             @Override\r
402             public boolean equals(java.lang.Object obj) {\r
403                 if (this == obj) {\r
404                     return true;\r
405                 }\r
406                 if (obj == null) {\r
407                     return false;\r
408                 }\r
409                 if (getClass() != obj.getClass()) {\r
410                     return false;\r
411                 }\r
412                 «type.name» other = («type.name») obj;\r
413                 «FOR property : genTO.equalsIdentifiers»\r
414                     «val fieldName = property.fieldName»\r
415                     if («fieldName» == null) {\r
416                         if (other.«fieldName» != null) {\r
417                             return false;\r
418                         }\r
419                     «IF property.returnType.name.contains("[")»\r
420                     } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {\r
421                     «ELSE»\r
422                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
423                     «ENDIF»\r
424                         return false;\r
425                     }\r
426                 «ENDFOR»\r
427                 return true;\r
428             }\r
429         «ENDIF»\r
430     '''\r
431 \r
432     def private generateGetLength() '''\r
433         «IF restrictions != null && !(restrictions.lengthConstraints.empty)»\r
434             public static «List.importedName»<«Range.importedName»<Integer>> getLength() {\r
435                 final «List.importedName»<«Range.importedName»<Integer>> result = new «ArrayList.importedName»<>();\r
436                 «FOR r : restrictions.lengthConstraints»\r
437                     result.add(«Range.importedName».closed(«r.min», «r.max»));\r
438                 «ENDFOR»\r
439                 return result;\r
440             }\r
441         «ENDIF»\r
442     '''\r
443 \r
444     def private generateGetRange() '''\r
445         «IF restrictions != null && !(restrictions.lengthConstraints.empty)»\r
446             public static «List.importedName»<«Range.importedName»<Integer>> getLength() {\r
447                 final «List.importedName»<«Range.importedName»<Integer>> result = new «ArrayList.importedName»<>();\r
448                 «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.importedName»<>(); \r
449                 «FOR r : restrictions.lengthConstraints»\r
450                     result.add(«Range.importedName».closed(«r.min», «r.max»));\r
451                 «ENDFOR»\r
452                 return result;\r
453             }\r
454         «ENDIF»\r
455     '''\r
456 \r
457 }\r