Merge "Added export of augmentation schemas to Binding Context"
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / BaseTemplate.xtend
1 package org.opendaylight.yangtools.sal.java.api.generator
2
3 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
4 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
5 import java.util.Map
6 import org.opendaylight.yangtools.sal.binding.model.api.Type
7 import org.opendaylight.yangtools.binding.generator.util.Types
8 import com.google.common.base.Splitter
9 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
10 import com.google.common.collect.Range
11 import java.util.ArrayList
12 import java.util.List
13 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
14 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
15 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
16 import java.util.Collection
17
18 abstract class BaseTemplate {
19
20     protected val GeneratedType type;
21     protected val Map<String, String> importMap;
22     static val paragraphSplitter = Splitter.on("\n\n").omitEmptyStrings();
23
24     new(GeneratedType _type) {
25         if (_type == null) {
26             throw new IllegalArgumentException("Generated type reference cannot be NULL!")
27         }
28         this.type = _type;
29         this.importMap = GeneratorUtil.createImports(type)
30     }
31
32     def packageDefinition() '''package «type.packageName»;'''
33
34     protected def getFullyQualifiedName() {
35         return type.fullyQualifiedName
36     }
37
38     final public def generate() {
39         val _body = body()
40         '''
41             «packageDefinition»
42             «imports»
43             
44             «_body»
45         '''.toString
46     }
47
48     protected def imports() ''' 
49         «IF !importMap.empty»
50             «FOR entry : importMap.entrySet»
51                 «IF entry.value != fullyQualifiedName»
52                     import «entry.value».«entry.key»;
53                 «ENDIF»
54             «ENDFOR»
55         «ENDIF»
56         
57     '''
58
59     protected abstract def CharSequence body();
60
61     // Helper patterns
62     final protected def fieldName(GeneratedProperty property) '''_«property.name»'''
63
64     final protected def propertyNameFromGetter(MethodSignature getter) {
65         var int prefix;
66         if (getter.name.startsWith("is")) {
67             prefix = 2
68         } else if (getter.name.startsWith("get")) {
69             prefix = 3
70         } else {
71             throw new IllegalArgumentException("Not a getter")
72         }
73         return getter.name.substring(prefix).toFirstLower;
74     }
75
76     /**
77      * Template method which generates the getter method for <code>field</code>
78      * 
79      * @param field 
80      * generated property with data about field which is generated as the getter method
81      * @return string with the getter method source code in JAVA format 
82      */
83     final protected def getterMethod(GeneratedProperty field) {
84         '''
85             public «field.returnType.importedName» «field.getterMethodName»() {
86                 return «field.fieldName»;
87             }
88         '''
89     }
90
91     final protected def getterMethodName(GeneratedProperty field) {
92         val prefix = if(field.returnType.equals(Types.BOOLEAN)) "is" else "get"
93         return '''«prefix»«field.name.toFirstUpper»'''
94     }
95
96     /**
97      * Template method which generates the setter method for <code>field</code>
98      * 
99      * @param field 
100      * generated property with data about field which is generated as the setter method
101      * @return string with the setter method source code in JAVA format 
102      */
103     final protected def setterMethod(GeneratedProperty field) '''
104         «val returnType = field.returnType.importedName»
105         public «type.name» set«field.name.toFirstUpper»(«returnType» value) {
106             this.«field.fieldName» = value;
107             return this;
108         }
109     '''
110
111     final protected def importedName(Type intype) {
112         GeneratorUtil.putTypeIntoImports(type, intype, importMap);
113         GeneratorUtil.getExplicitType(type, intype, importMap)
114     }
115
116     final protected def importedName(Class<?> cls) {
117         importedName(Types.typeForClass(cls))
118     }
119
120     /**
121      * Template method which generates method parameters with their types from <code>parameters</code>.
122      * 
123      * @param parameters
124      * group of generated property instances which are transformed to the method parameters
125      * @return string with the list of the method parameters with their types in JAVA format
126      */
127     def final protected asArgumentsDeclaration(Iterable<GeneratedProperty> parameters) '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.
128         returnType.importedName» «parameter.fieldName»«ENDFOR»«ENDIF»'''
129
130     /**
131      * Template method which generates sequence of the names of the class attributes from <code>parameters</code>.
132      * 
133      * @param parameters 
134      * group of generated property instances which are transformed to the sequence of parameter names
135      * @return string with the list of the parameter names of the <code>parameters</code> 
136      */
137     def final protected asArguments(Iterable<GeneratedProperty> parameters) '''«IF !parameters.empty»«FOR parameter : parameters SEPARATOR ", "»«parameter.
138         fieldName»«ENDFOR»«ENDIF»'''
139
140     /**
141      * Template method which generates JAVA comments.
142      * 
143      * @param comment string with the comment for whole JAVA class
144      * @return string with comment in JAVA format
145      */
146     def protected CharSequence asJavadoc(String comment) {
147         if(comment == null) return '';
148         val paragraphs = paragraphSplitter.split(comment)
149
150         return '''
151             /**
152               «FOR p : paragraphs SEPARATOR "<p>"»
153                   «p»
154               «ENDFOR»
155             **/
156         '''
157     }
158
159     def generateRestrictions(Type type, String paramName, Type returnType) '''
160         «val boolean isArray = returnType.name.contains("[")»
161         «processRestrictions(type, paramName, returnType, isArray)»
162     '''
163
164     def generateRestrictions(GeneratedProperty field, String paramName) '''
165         «val Type type = field.returnType»
166         «IF type instanceof ConcreteType»
167             «processRestrictions(type, paramName, field.returnType, type.name.contains("["))»
168         «ELSEIF type instanceof GeneratedTransferObject»
169             «processRestrictions(type, paramName, field.returnType, isArrayType(type as GeneratedTransferObject))»
170         «ENDIF»
171     '''
172
173
174     private def processRestrictions(Type type, String paramName, Type returnType, boolean isArray) '''
175         «val restrictions = type.getRestrictions»
176         «IF restrictions !== null»
177             «IF !restrictions.lengthConstraints.empty»
178                 «generateLengthRestriction(type, restrictions, paramName, isArray,
179             !(returnType instanceof ConcreteType))»
180             «ENDIF»
181             «IF !restrictions.rangeConstraints.empty &&
182             ("java.lang".equals(returnType.packageName) || "java.math".equals(returnType.packageName))»
183                 «generateRangeRestriction(type, returnType, restrictions, paramName,
184             !(returnType instanceof ConcreteType))»
185             «ENDIF»
186         «ENDIF»
187     '''
188
189     def generateLengthRestriction(Type type, Restrictions restrictions, String paramName, boolean isArray,
190         boolean isNestedType) '''
191         if («paramName» != null) {
192             boolean isValidLength = false;
193             «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.
194             importedName»<>(); 
195             «FOR r : restrictions.lengthConstraints»
196                 lengthConstraints.add(«Range.importedName».closed(«r.min», «r.max»));
197             «ENDFOR»
198             for («Range.importedName»<«Integer.importedName»> r : lengthConstraints) {
199                 «IF isArray»
200                     «IF isNestedType»
201                         if (r.contains(«paramName».getValue().length)) {
202                     «ELSE»
203                         if (r.contains(«paramName».length)) {
204                     «ENDIF»
205                 «ELSE»
206                     «IF isNestedType»
207                         if (r.contains(«paramName».getValue().length())) {
208                     «ELSE»
209                         if (r.contains(«paramName».length())) {
210                     «ENDIF»
211                 «ENDIF»
212                 isValidLength = true;
213                 }
214             }
215             if (!isValidLength) {
216                 throw new IllegalArgumentException("illegal length");
217             }
218         }
219     '''
220
221     def generateRangeRestriction(Type type, Type returnType, Restrictions restrictions, String paramName,
222         boolean isNestedType) '''
223         «val javaType = Class.forName(returnType.fullyQualifiedName)»
224         if («paramName» != null) {
225             boolean isValidRange = false;
226             «List.importedName»<«Range.importedName»<«javaType.importedName»>> rangeConstraints = new «ArrayList.
227             importedName»<>(); 
228             «FOR r : restrictions.rangeConstraints»
229                 rangeConstraints.add(«Range.importedName».closed(new «javaType.importedName»(«r.min.toQuote»), new «javaType.
230             importedName»(«r.max.toQuote»)));
231             «ENDFOR»
232             for («Range.importedName»<«javaType.importedName»> r : rangeConstraints) {
233                 «IF isNestedType»
234                     if (r.contains(«paramName».getValue())) {
235                 «ELSE»
236                     if (r.contains(«paramName»)) {
237                 «ENDIF»
238                 isValidRange = true;
239                 }
240             }
241             if (!isValidRange) {
242                 throw new IllegalArgumentException("illegal length");
243             }
244         }
245     '''
246
247     def GeneratedProperty getPropByName(GeneratedType gt, String name) {
248         for (GeneratedProperty prop : gt.properties) {
249             if (prop.name.equals(name)) {
250                 return prop;
251             }
252         }
253         return null;
254     }
255
256     def GeneratedProperty getPropByName(Collection<GeneratedProperty> props, String name) {
257         for (GeneratedProperty prop : props) {
258             if (prop.name.equals(name)) {
259                 return prop;
260             }
261         }
262         return null;
263     }
264
265     def getRestrictions(Type type) {
266         var Restrictions restrictions = null
267         if (type instanceof ConcreteType) {
268             restrictions = (type as ConcreteType).restrictions
269         } else if (type instanceof GeneratedTransferObject) {
270             restrictions = (type as GeneratedTransferObject).restrictions
271         }
272         return restrictions
273     }
274
275     def boolean isArrayType(GeneratedTransferObject type) {
276         var isArray = false
277         val GeneratedTransferObject superType = type.findSuperType
278         val GeneratedProperty value = superType.getPropByName("value")
279         if (value != null && value.returnType.name.contains("[")) {
280             isArray = true
281         }
282         return isArray
283     }
284
285     def GeneratedTransferObject findSuperType(GeneratedTransferObject gto) {
286         var GeneratedTransferObject base = gto
287         var GeneratedTransferObject superType = base.superType
288         while (superType !== null) {
289             base = superType
290             superType = base.superType
291         }
292         return base;
293     }
294
295     def String toQuote(Object obj) {
296         return "\"" + obj.toString + "\"";
297     }
298
299 }