Teach MethodSignature about default methods
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / InterfaceTemplate.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.mdsal.binding.java.api.generator
9
10 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getGetterMethodForNonnull
11 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isGetterMethodName
12 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.isNonnullMethodName
13
14 import java.util.List
15 import org.opendaylight.mdsal.binding.model.api.AnnotationType
16 import org.opendaylight.mdsal.binding.model.api.Constant
17 import org.opendaylight.mdsal.binding.model.api.Enumeration
18 import org.opendaylight.mdsal.binding.model.api.GeneratedType
19 import org.opendaylight.mdsal.binding.model.api.JavaTypeName
20 import org.opendaylight.mdsal.binding.model.api.MethodSignature
21 import org.opendaylight.mdsal.binding.model.api.Type
22 import org.opendaylight.mdsal.binding.model.util.TypeConstants
23 import org.opendaylight.yangtools.yang.binding.CodeHelpers
24
25 /**
26  * Template for generating JAVA interfaces.
27  */
28 class InterfaceTemplate extends BaseTemplate {
29     static val JavaTypeName NONNULL = JavaTypeName.create("org.eclipse.jdt.annotation", "NonNull")
30     static val JavaTypeName NULLABLE = JavaTypeName.create("org.eclipse.jdt.annotation", "Nullable")
31
32     /**
33      * List of constant instances which are generated as JAVA public static final attributes.
34      */
35     val List<Constant> consts
36
37     /**
38      * List of method signatures which are generated as method declarations.
39      */
40     val List<MethodSignature> methods
41
42     /**
43      * List of enumeration which are generated as JAVA enum type.
44      */
45     val List<Enumeration> enums
46
47     /**
48      * List of generated types which are enclosed inside <code>genType</code>
49      */
50     val List<GeneratedType> enclosedGeneratedTypes
51
52     /**
53      * Creates the instance of this class which is used for generating the interface file source
54      * code from <code>genType</code>.
55      *
56      * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
57      */
58     new(GeneratedType genType) {
59         super(genType)
60         if (genType === null) {
61             throw new IllegalArgumentException("Generated type reference cannot be NULL!")
62         }
63
64         consts = genType.constantDefinitions
65         methods = genType.methodDefinitions
66         enums = genType.enumerations
67         enclosedGeneratedTypes = genType.enclosedTypes
68     }
69
70     /**
71      * Template method which generate the whole body of the interface.
72      *
73      * @return string with code for interface body in JAVA format
74      */
75     override body() '''
76         «wrapToDocumentation(formatDataForJavaDoc(type))»
77         «type.annotations.generateAnnotations»
78         public interface «type.name»
79             «superInterfaces»
80         {
81
82             «generateInnerClasses»
83
84             «generateEnums»
85
86             «generateConstants»
87
88             «generateMethods»
89
90         }
91
92     '''
93
94
95     def private generateAnnotations(List<AnnotationType> annotations) '''
96         «IF annotations !== null && !annotations.empty»
97             «FOR annotation : annotations»
98                 @«annotation.importedName»
99                 «IF annotation.parameters !== null && !annotation.parameters.empty»
100                 (
101                 «FOR param : annotation.parameters SEPARATOR ","»
102                     «param.name»=«param.value»
103                 «ENDFOR»
104                 )
105                 «ENDIF»
106             «ENDFOR»
107         «ENDIF»
108     '''
109
110     /**
111      * Template method which generates the interface name declaration.
112      *
113      * @return string with the code for the interface declaration in JAVA format
114      */
115     def private superInterfaces()
116     '''
117     «IF (!type.implements.empty)»
118          extends
119          «FOR type : type.implements SEPARATOR ","»
120              «type.importedName»
121          «ENDFOR»
122      « ENDIF»
123      '''
124
125     /**
126      * Template method which generates inner classes inside this interface.
127      *
128      * @return string with the source code for inner classes in JAVA format
129      */
130     def private generateInnerClasses() '''
131         «IF !enclosedGeneratedTypes.empty»
132             «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
133                 «generateInnerClass(innerClass)»
134             «ENDFOR»
135         «ENDIF»
136     '''
137
138     /**
139      * Template method which generates JAVA enum type.
140      *
141      * @return string with inner enum source code in JAVA format
142      */
143     def private generateEnums() '''
144         «IF !enums.empty»
145             «FOR e : enums SEPARATOR "\n"»
146                 «val enumTemplate = new EnumTemplate(javaType.getEnclosedType(e.identifier), e)»
147                 «enumTemplate.generateAsInnerClass»
148             «ENDFOR»
149         «ENDIF»
150     '''
151
152     /**
153      * Template method wich generates JAVA constants.
154      *
155      * @return string with constants in JAVA format
156      */
157     def private generateConstants() '''
158         «IF !consts.empty»
159             «FOR c : consts»
160                 «IF !c.name.startsWith(TypeConstants.PATTERN_CONSTANT_NAME)»
161                     «emitConstant(c)»
162                 «ENDIF»
163             «ENDFOR»
164         «ENDIF»
165     '''
166
167     /**
168      * Template method which generates the declaration of the methods.
169      *
170      * @return string with the declaration of methods source code in JAVA format
171      */
172     def private generateMethods() '''
173         «IF !methods.empty»
174             «FOR m : methods SEPARATOR "\n"»
175                 «IF m.isDefault»
176                     «generateDefaultMethod(m)»
177                 «ELSEIF m.parameters.empty && m.name.isGetterMethodName»
178                     «generateAccessorMethod(m)»
179                 «ELSE»
180                     «generateMethod(m)»
181                 «ENDIF»
182             «ENDFOR»
183         «ENDIF»
184     '''
185
186     def private generateDefaultMethod(MethodSignature method) {
187         if (method.name.isNonnullMethodName) {
188             return generateNonnullMethod(method)
189         }
190     }
191
192     def private generateMethod(MethodSignature method) '''
193         «method.comment.asJavadoc»
194         «method.annotations.generateAnnotations»
195         «method.returnType.importedName» «method.name»(«method.parameters.generateParameters»);
196     '''
197
198     def private generateAccessorMethod(MethodSignature method) '''
199         «val ret = method.returnType»
200         «formatDataForJavaDoc(method, "@return " + asCode(ret.fullyQualifiedName) + " " + asCode(propertyNameFromGetter(method)) + ", or " + asCode("null") + " if not present")»
201         «method.annotations.generateAnnotations»
202         «nullableType(ret)» «method.name»();
203     '''
204
205     def private generateNonnullMethod(MethodSignature method) '''
206         «val ret = method.returnType»
207         «val name = method.name»
208         «formatDataForJavaDoc(method, "@return " + asCode(ret.fullyQualifiedName) + " " + asCode(propertyNameFromGetter(method)) + ", or an empty list if it is not present")»
209         «method.annotations.generateAnnotations»
210         default «ret.importedName(NONNULL.importedName)» «name»() {
211             return «CodeHelpers.importedName».nonnull(«getGetterMethodForNonnull(name)»());
212         }
213     '''
214
215     def private String nullableType(Type type) {
216         if (type.isObject) {
217             return type.importedName(NULLABLE.importedName)
218         }
219         return type.importedName
220     }
221
222     def private static boolean isObject(Type type) {
223         // The return type has a package, so it's not a primitive type
224         return !type.getPackageName().isEmpty()
225     }
226 }