Implemented support for generating YangModuleInfo implementation.
[yangtools.git] / code-generator / 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 org.opendaylight.yangtools.yang.model.api.Module
11 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil
12 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
13 import java.io.InputStream
14 import com.google.common.collect.ImmutableSet
15 import java.util.Map
16 import java.util.LinkedHashMap
17 import org.opendaylight.yangtools.binding.generator.util.Types
18 import org.opendaylight.yangtools.sal.binding.model.api.Type
19 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
20 import org.opendaylight.yangtools.sal.binding.model.api.WildcardType
21 import java.io.IOException
22 import java.util.Set
23 import java.util.HashSet
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext
25 import java.util.Date
26 import java.util.TreeMap
27 import java.text.DateFormat
28 import java.text.SimpleDateFormat
29
30 class YangModuleInfoTemplate {
31     val CLASS = "$YangModuleInfoImpl"
32
33     val Module module
34     val SchemaContext ctx
35     val Map<String, String> importMap = new LinkedHashMap()
36
37     new (Module module, SchemaContext ctx) {
38         if (module == null) {
39             throw new IllegalArgumentException("Module reference cannot be NULL!")
40         }
41         this.module = module
42         this.ctx = ctx
43     }
44
45     def String generate() {
46         val String classBody = body().toString
47         '''
48         package «BindingGeneratorUtil.moduleNamespaceToPackageName(module)» ;
49
50         «imports»
51
52         «classBody»
53         '''.toString
54     }
55
56     def body() '''
57         public class «CLASS» implements «YangModuleInfo.importedName» {
58
59             private static final «YangModuleInfo.importedName» INSTANCE = new «CLASS»();
60
61             private «CLASS»() {}
62
63             public static «YangModuleInfo.importedName» getInstance() {
64                 return INSTANCE;
65             }
66
67             «module.classBody»
68
69         }
70     '''
71
72     private def CharSequence classBody(Module m) '''
73         @Override
74             public «String.importedName» getName() {
75             return "«m.name»";
76         }
77
78         @Override
79         public «String.importedName» getRevision() {
80             «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
81             return "«df.format(m.revision)»";
82         }
83
84         @Override
85         public «String.importedName» getNamespace() {
86             return "«m.namespace.toString»";
87         }
88
89         @Override
90         public «InputStream.importedName» getModuleSourceStream() throws «IOException.importedName» {
91             «val path = m.moduleSourcePath»
92             «IF path == null»
93                 return null;
94             «ELSE»
95                 return «CLASS».class.getResourceAsStream("«path»");
96             «ENDIF»
97         }
98
99         @Override
100         public «ImmutableSet.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
101             «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
102             «FOR imp : m.imports»
103                 «val name = imp.moduleName»
104                 «val rev = imp.revision»
105                 «IF rev == null»
106                     «val Set<Module> modules = ctx.modules»
107                     «val TreeMap<Date, Module> sorted = new TreeMap()»
108                     «FOR module : modules»
109                         «IF module.name.equals(name)»
110                             «sorted.put(module.revision, module)»
111                         «ENDIF»
112                     «ENDFOR»
113                     set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(sorted.lastEntry().value)».«CLASS».getInstance());
114                 «ELSE»
115                     set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(ctx.findModuleByName(name, rev))».«CLASS».getInstance());
116                 «ENDIF»
117             «ENDFOR»
118             return «ImmutableSet.importedName».copyOf(set);
119         }
120     '''
121
122     private def imports() ''' 
123         «IF !importMap.empty»
124             «FOR entry : importMap.entrySet»
125                 «IF entry.value != BindingGeneratorUtil.moduleNamespaceToPackageName(module)»
126                     import «entry.value».«entry.key»;
127                 «ENDIF»
128             «ENDFOR»
129         «ENDIF»
130         
131     '''
132
133     final protected def importedName(Class<?> cls) {
134         val Type intype = Types.typeForClass(cls)
135         putTypeIntoImports(intype);
136         getExplicitType(intype)
137     }
138
139     final def void putTypeIntoImports(Type type) {
140         val String typeName = type.getName();
141         val String typePackageName = type.getPackageName();
142         if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
143             return;
144         }
145         if (!importMap.containsKey(typeName)) {
146             importMap.put(typeName, typePackageName);
147         }
148         if (type instanceof ParameterizedType) {
149             val ParameterizedType paramType = (type as ParameterizedType)
150             val Type[] params = paramType.getActualTypeArguments()
151             if (params != null) {
152                 for (Type param : params) {
153                     putTypeIntoImports(param);
154                 }
155             }
156         }
157     }
158
159     final def String getExplicitType(Type type) {
160         val String typePackageName = type.getPackageName();
161         val String typeName = type.getName();
162         val String importedPackageName = importMap.get(typeName);
163         var StringBuilder builder;
164         if (typePackageName.equals(importedPackageName)) {
165             builder = new StringBuilder(type.getName());
166             addActualTypeParameters(builder, type);
167             if (builder.toString().equals("Void")) {
168                 return "void";
169             }
170         } else {
171             builder = new StringBuilder();
172             if (typePackageName.startsWith("java.lang")) {
173                 builder.append(type.getName());
174             } else {
175                 if (!typePackageName.isEmpty()) {
176                     builder.append(typePackageName + Constants.DOT + type.getName());
177                 } else {
178                     builder.append(type.getName());
179                 }
180             }
181             if (type.equals(Types.voidType())) {
182                 return "void";
183             }
184             addActualTypeParameters(builder, type);
185         }
186         return builder.toString();
187     }
188
189     final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
190         if (type instanceof ParameterizedType) {
191             val ParameterizedType pType = (type as ParameterizedType)
192             val Type[] pTypes = pType.getActualTypeArguments();
193             builder.append("<");
194             builder.append(getParameters(pTypes));
195             builder.append(">");
196         }
197         return builder;
198     }
199
200     final def String getParameters(Type[] pTypes) {
201         if (pTypes == null || pTypes.length == 0) {
202             return "?";
203         }
204         val StringBuilder builder = new StringBuilder();
205         
206         var int i = 0;
207         for (pType : pTypes) {
208             val Type t = pTypes.get(i)
209
210             var String separator = ",";
211             if (i == (pTypes.length - 1)) {
212                 separator = "";
213             }
214
215             var String wildcardParam = "";
216             if (t.equals(Types.voidType())) {
217                 builder.append("java.lang.Void" + separator);
218             } else {
219
220                 if (t instanceof WildcardType) {
221                     wildcardParam = "? extends ";
222                 }
223
224                 builder.append(wildcardParam + getExplicitType(t) + separator);
225                 i = i + 1
226             }
227         }
228         return builder.toString();
229     }
230
231 }