Bug 6165: Do not omit java.lang prefix in various places
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / YangModuleInfoTemplate.xtend
1 /*
2  * Copyright (c) 2013 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
9
10 import java.io.InputStream
11 import java.io.IOException
12 import java.text.DateFormat
13 import java.text.SimpleDateFormat
14
15 import java.util.Collections
16 import java.util.Date
17 import java.util.HashSet
18 import java.util.LinkedHashMap
19 import java.util.Map
20 import java.util.Set
21 import java.util.TreeMap
22
23 import org.opendaylight.yangtools.binding.generator.util.Types
24 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
25 import org.opendaylight.yangtools.sal.binding.model.api.Type
26 import org.opendaylight.yangtools.sal.binding.model.api.WildcardType
27 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
28 import org.opendaylight.yangtools.yang.model.api.Module
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext
30
31 import com.google.common.collect.ImmutableSet
32 import static org.opendaylight.yangtools.yang.binding.BindingMapping.*
33 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
34 import com.google.common.base.Preconditions
35
36 class YangModuleInfoTemplate {
37
38     val Module module
39     val SchemaContext ctx
40     val Map<String, String> importMap = new LinkedHashMap()
41
42     @Property
43     val String packageName;
44
45     @Property
46     val String modelBindingProviderName;
47
48     new(Module module, SchemaContext ctx) {
49         Preconditions.checkArgument(module != null, "Module must not be null.");
50         this.module = module
51         this.ctx = ctx
52         _packageName = getRootPackageName(module.getQNameModule());
53         _modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»''';
54     }
55
56     def String generate() {
57         val body = '''
58             public final class «MODULE_INFO_CLASS_NAME» implements «YangModuleInfo.importedName» {
59
60                 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
61
62                 private final «String.importedName» name = "«module.name»";
63                 private final «String.importedName» namespace = "«module.namespace.toString»";
64                 «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
65                 private final «String.importedName» revision = "«df.format(module.revision)»";
66                 private final «String.importedName» resourcePath = "«sourcePath»";
67
68                 private final «Set.importedName»<YangModuleInfo> importedModules;
69
70                 public static «YangModuleInfo.importedName» getInstance() {
71                     return INSTANCE;
72                 }
73
74                 «classBody(module, MODULE_INFO_CLASS_NAME)»
75             }
76         '''
77         return '''
78             package «packageName» ;
79             «imports»
80             «body»
81         '''.toString
82     }
83
84     def String generateModelProvider() {
85         '''
86             package «packageName»;
87
88             public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
89
90                 public «YangModuleInfo.name» getModuleInfo() {
91                     return «MODULE_INFO_CLASS_NAME».getInstance();
92                 }
93             }
94         '''
95
96     }
97
98     private def CharSequence classBody(Module m, String className) '''
99         private «className»() {
100             «IF !m.imports.empty || !m.submodules.empty»
101                 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
102             «ENDIF»
103             «IF !m.imports.empty»
104                 «FOR imp : m.imports»
105                     «val name = imp.moduleName»
106                     «val rev = imp.revision»
107                     «IF rev == null»
108                         «val Set<Module> modules = ctx.modules»
109                         «val TreeMap<Date, Module> sorted = new TreeMap()»
110                         «FOR module : modules»
111                             «IF module.name.equals(name)»
112                                 «sorted.put(module.revision, module)»
113                             «ENDIF»
114                         «ENDFOR»
115                         set.add(«getRootPackageName(sorted.lastEntry().value.QNameModule)».«MODULE_INFO_CLASS_NAME».getInstance());
116                     «ELSE»
117                         set.add(«getRootPackageName((ctx.findModuleByName(name, rev).QNameModule))».«MODULE_INFO_CLASS_NAME».getInstance());
118                     «ENDIF»
119                 «ENDFOR»
120             «ENDIF»
121             «IF !m.submodules.empty»
122                 «FOR submodule : m.submodules»
123                     set.add(«getClassName(submodule.name)»Info.getInstance());
124                 «ENDFOR»
125             «ENDIF»
126             «IF m.imports.empty && m.submodules.empty»
127                 importedModules = «Collections.importedName».emptySet();
128             «ELSE»
129                 importedModules = «ImmutableSet.importedName».copyOf(set);
130             «ENDIF»
131
132             «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
133             if (stream == null) {
134                 throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
135             }
136             try {
137                 stream.close();
138             } catch («IOException.importedName» e) {
139             // Resource leak, but there is nothing we can do
140             }
141         }
142
143         @Override
144         public «String.importedName» getName() {
145             return name;
146         }
147
148         @Override
149         public «String.importedName» getRevision() {
150             return revision;
151         }
152
153         @Override
154         public «String.importedName» getNamespace() {
155             return namespace;
156         }
157
158         @Override
159         public «InputStream.importedName» getModuleSourceStream() throws IOException {
160             «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
161             if (stream == null) {
162                 throw new «IOException.importedName»("Resource " + resourcePath + " is missing");
163             }
164             return stream;
165         }
166
167         @Override
168         public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
169             return importedModules;
170         }
171
172         @Override
173         public «String.importedName» toString() {
174             «StringBuilder.importedName» sb = new «StringBuilder.importedName»(this.getClass().getCanonicalName());
175             sb.append("[");
176             sb.append("name = " + name);
177             sb.append(", namespace = " + namespace);
178             sb.append(", revision = " + revision);
179             sb.append(", resourcePath = " + resourcePath);
180             sb.append(", imports = " + importedModules);
181             sb.append("]");
182             return sb.toString();
183         }
184
185         «generateSubInfo(m)»
186
187     '''
188
189     def getSourcePath() {
190         return "/" + module.moduleSourcePath.replace(java.io.File.separatorChar, '/')
191     }
192
193     private def imports() '''
194         «IF !importMap.empty»
195             «FOR entry : importMap.entrySet»
196                 «IF entry.value != getRootPackageName(module.QNameModule)»
197                     import «entry.value».«entry.key»;
198                 «ENDIF»
199             «ENDFOR»
200         «ENDIF»
201     '''
202
203     final protected def importedName(Class<?> cls) {
204         val Type intype = Types.typeForClass(cls)
205         putTypeIntoImports(intype);
206         getExplicitType(intype)
207     }
208
209     final def void putTypeIntoImports(Type type) {
210         val String typeName = type.getName();
211         val String typePackageName = type.getPackageName();
212         if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
213             return;
214         }
215         if (!importMap.containsKey(typeName)) {
216             importMap.put(typeName, typePackageName);
217         }
218         if (type instanceof ParameterizedType) {
219             val Type[] params = type.getActualTypeArguments()
220             if (params != null) {
221                 for (Type param : params) {
222                     putTypeIntoImports(param);
223                 }
224             }
225         }
226     }
227
228     final def String getExplicitType(Type type) {
229         val String typePackageName = type.getPackageName();
230         val String typeName = type.getName();
231         val String importedPackageName = importMap.get(typeName);
232         var StringBuilder builder;
233         if (typePackageName.equals(importedPackageName)) {
234             builder = new StringBuilder(type.getName());
235             if (builder.toString().equals("Void")) {
236                 return "void";
237             }
238             addActualTypeParameters(builder, type);
239         } else {
240             if (type.equals(Types.voidType())) {
241                 return "void";
242             }
243             builder = new StringBuilder();
244             if (!typePackageName.isEmpty()) {
245                 builder.append(typePackageName + Constants.DOT + type.getName());
246             } else {
247                 builder.append(type.getName());
248             }
249             addActualTypeParameters(builder, type);
250         }
251         return builder.toString();
252     }
253
254     final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
255         if (type instanceof ParameterizedType) {
256             val Type[] pTypes = type.getActualTypeArguments();
257             builder.append('<');
258             builder.append(getParameters(pTypes));
259             builder.append('>');
260         }
261         return builder;
262     }
263
264     final def String getParameters(Type[] pTypes) {
265         if (pTypes == null || pTypes.length == 0) {
266             return "?";
267         }
268         val StringBuilder builder = new StringBuilder();
269
270         var int i = 0;
271         for (pType : pTypes) {
272             val Type t = pTypes.get(i)
273
274             var String separator = ",";
275             if (i == (pTypes.length - 1)) {
276                 separator = "";
277             }
278
279             var String wildcardParam = "";
280             if (t.equals(Types.voidType())) {
281                 builder.append("java.lang.Void" + separator);
282             } else {
283
284                 if (t instanceof WildcardType) {
285                     wildcardParam = "? extends ";
286                 }
287
288                 builder.append(wildcardParam + getExplicitType(t) + separator);
289                 i = i + 1
290             }
291         }
292         return builder.toString();
293     }
294
295     private def generateSubInfo(Module module) '''
296         «FOR submodule : module.submodules»
297             private static final class «getClassName(submodule.name)»Info implements «YangModuleInfo.importedName» {
298
299                 private static final «YangModuleInfo.importedName» INSTANCE = new «getClassName(submodule.name)»Info();
300
301                 private final «String.importedName» name = "«submodule.name»";
302                 private final «String.importedName» namespace = "«submodule.namespace.toString»";
303                 «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
304                 private final «String.importedName» revision = "«df.format(submodule.revision)»";
305                 private final «String.importedName» resourcePath = "/«submodule.moduleSourcePath.replace(java.io.File.separatorChar, '/')»";
306
307                 private final «Set.importedName»<YangModuleInfo> importedModules;
308
309                 public static «YangModuleInfo.importedName» getInstance() {
310                     return INSTANCE;
311                 }
312
313                 «classBody(submodule, getClassName(submodule.name + "Info"))»
314             }
315         «ENDFOR»
316     '''
317
318 }