Cleanup YangModuleInfoTemplate
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / 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.mdsal.binding.java.api.generator
9
10 import static org.opendaylight.yangtools.yang.binding.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME
11 import static org.opendaylight.yangtools.yang.binding.BindingMapping.MODULE_INFO_CLASS_NAME
12 import static extension org.opendaylight.yangtools.yang.binding.BindingMapping.getClassName
13 import static extension org.opendaylight.yangtools.yang.binding.BindingMapping.getRootPackageName
14
15 import com.google.common.base.Preconditions
16 import com.google.common.collect.ImmutableSet
17 import java.util.Collections
18 import java.util.HashSet
19 import java.util.LinkedHashMap
20 import java.util.Map
21 import java.util.Optional
22 import java.util.Set
23 import java.util.TreeMap
24 import java.util.function.Function
25 import org.eclipse.xtend.lib.annotations.Accessors
26 import org.opendaylight.mdsal.binding.model.api.ParameterizedType
27 import org.opendaylight.mdsal.binding.model.api.Type
28 import org.opendaylight.mdsal.binding.model.api.WildcardType
29 import org.opendaylight.mdsal.binding.model.util.Types
30 import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo
31 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
32 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
33 import org.opendaylight.yangtools.yang.common.QName
34 import org.opendaylight.yangtools.yang.common.Revision
35 import org.opendaylight.yangtools.yang.model.api.Module
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext
37
38 class YangModuleInfoTemplate {
39
40     val Module module
41     val SchemaContext ctx
42     val Map<String, String> importMap = new LinkedHashMap()
43     val Function<Module, Optional<String>> moduleFilePathResolver
44
45     @Accessors
46     val String packageName
47
48     @Accessors
49     val String modelBindingProviderName
50
51     new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
52         Preconditions.checkArgument(module !== null, "Module must not be null.")
53         this.module = module
54         this.ctx = ctx
55         this.moduleFilePathResolver = moduleFilePathResolver
56         packageName = module.QNameModule.rootPackageName;
57         modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
58     }
59
60     def String generate() {
61         val body = '''
62             public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
63
64                 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
65
66                 «val rev = module.revision»
67                 private final «QName.importedName» name = QName.create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
68                 private final «Set.importedName»<«YangModuleInfo.importedName»> 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
80             «imports»
81
82             «body»
83         '''.toString
84     }
85
86     def String generateModelProvider() {
87         '''
88             package «packageName»;
89
90             public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
91                 @Override
92                 public «YangModuleInfo.name» getModuleInfo() {
93                     return «MODULE_INFO_CLASS_NAME».getInstance();
94                 }
95             }
96         '''
97
98     }
99
100     private def CharSequence classBody(Module m, String className) '''
101         private «className»() {
102             «IF !m.imports.empty || !m.submodules.empty»
103                 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
104             «ENDIF»
105             «IF !m.imports.empty»
106                 «FOR imp : m.imports»
107                     «val name = imp.moduleName»
108                     «val rev = imp.revision»
109                     «IF !rev.present»
110                         «val Set<Module> modules = ctx.modules»
111                         «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap()»
112                         «FOR module : modules»
113                             «IF module.name.equals(name)»
114                                 «sorted.put(module.revision, module)»
115                             «ENDIF»
116                         «ENDFOR»
117                         set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
118                     «ELSE»
119                         set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
120                     «ENDIF»
121                 «ENDFOR»
122             «ENDIF»
123             «IF !m.submodules.empty»
124                 «FOR submodule : m.submodules»
125                     set.add(«submodule.name.className»Info.getInstance());
126                 «ENDFOR»
127             «ENDIF»
128             «IF m.imports.empty && m.submodules.empty»
129                 importedModules = «Collections.importedName».emptySet();
130             «ELSE»
131                 importedModules = «ImmutableSet.importedName».copyOf(set);
132             «ENDIF»
133         }
134
135         @Override
136         public «QName.importedName» getName() {
137             return name;
138         }
139
140         @Override
141         protected «String.importedName» resourceName() {
142             return "«sourcePath(m)»";
143         }
144
145         @Override
146         public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
147             return importedModules;
148         }
149
150         «generateSubInfo(m)»
151
152     '''
153
154     private def sourcePath(Module module) {
155         val opt = moduleFilePathResolver.apply(module)
156         Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
157         return opt.get
158     }
159
160     private def imports() '''
161         «IF !importMap.empty»
162             «FOR entry : importMap.entrySet»
163                 «IF entry.value != module.QNameModule.rootPackageName»
164                     import «entry.value».«entry.key»;
165                 «ENDIF»
166             «ENDFOR»
167         «ENDIF»
168     '''
169
170     final protected def importedName(Class<?> cls) {
171         val Type intype = Types.typeForClass(cls)
172         putTypeIntoImports(intype)
173         intype.explicitType
174     }
175
176     final def void putTypeIntoImports(Type type) {
177         val String typeName = type.name
178         val String typePackageName = type.packageName
179         if (typePackageName.startsWith("java.lang") || typePackageName.empty) {
180             return
181         }
182         if (!importMap.containsKey(typeName)) {
183             importMap.put(typeName, typePackageName)
184         }
185         if (type instanceof ParameterizedType) {
186             val Type[] params = type.actualTypeArguments
187             if (params !== null) {
188                 for (Type param : params) {
189                     putTypeIntoImports(param)
190                 }
191             }
192         }
193     }
194
195     final def String getExplicitType(Type type) {
196         val String typePackageName = type.packageName
197         val String typeName = type.name
198         val String importedPackageName = importMap.get(typeName)
199         var StringBuilder builder
200         if (typePackageName.equals(importedPackageName)) {
201             builder = new StringBuilder(typeName)
202             if (builder.toString().equals("Void")) {
203                 return "void"
204             }
205             addActualTypeParameters(builder, type)
206         } else {
207             if (type.equals(Types.voidType())) {
208                 return "void"
209             }
210             builder = new StringBuilder()
211             if (!typePackageName.empty) {
212                 builder.append(typePackageName).append(Constants.DOT).append(typeName)
213             } else {
214                 builder.append(typeName)
215             }
216             addActualTypeParameters(builder, type)
217         }
218         return builder.toString()
219     }
220
221     final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
222         if (type instanceof ParameterizedType) {
223             val Type[] pTypes = type.actualTypeArguments
224             builder.append('<').append(getParameters(pTypes)).append('>')
225         }
226         return builder
227     }
228
229     final def String getParameters(Type[] pTypes) {
230         if (pTypes === null || pTypes.length == 0) {
231             return "?"
232         }
233         val StringBuilder builder = new StringBuilder()
234
235         var int i = 0
236         for (pType : pTypes) {
237             val Type t = pTypes.get(i)
238
239             var String separator = ","
240             if (i == (pTypes.length - 1)) {
241                 separator = ""
242             }
243
244             var String wildcardParam = ""
245             if (t.equals(Types.voidType())) {
246                 builder.append("java.lang.Void").append(separator)
247             } else {
248
249                 if (t instanceof WildcardType) {
250                     wildcardParam = "? extends "
251                 }
252
253                 builder.append(wildcardParam).append(t.explicitType).append(separator)
254                 i = i + 1
255             }
256         }
257         return builder.toString()
258     }
259
260     private def generateSubInfo(Module module) '''
261         «FOR submodule : module.submodules»
262             «val className = submodule.name.className»
263             private static final class «className»Info extends «ResourceYangModuleInfo.importedName» {
264
265                 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
266
267                 «val rev = submodule.revision»
268                 private final «QName.importedName» name = QName.create("«submodule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF» "«submodule.name»").intern();
269                 private final «Set.importedName»<YangModuleInfo> importedModules;
270
271                 public static «YangModuleInfo.importedName» getInstance() {
272                     return INSTANCE;
273                 }
274
275                 «classBody(submodule, className + "Info")»
276             }
277         «ENDFOR»
278     '''
279 }