2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.sal.java.api.generator
10 import java.io.InputStream
11 import java.io.IOException
12 import java.text.DateFormat
13 import java.text.SimpleDateFormat
15 import java.util.Collections
17 import java.util.HashSet
18 import java.util.LinkedHashMap
21 import java.util.TreeMap
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
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
36 class YangModuleInfoTemplate {
40 val Map<String, String> importMap = new LinkedHashMap()
43 val String packageName;
46 val String modelBindingProviderName;
48 new(Module module, SchemaContext ctx) {
49 Preconditions.checkArgument(module != null, "Module must not be null.");
52 _packageName = getRootPackageName(module.getQNameModule());
53 _modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»''';
56 def String generate() {
58 public final class «MODULE_INFO_CLASS_NAME» implements «YangModuleInfo.importedName» {
60 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
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»";
68 private final «Set.importedName»<YangModuleInfo> importedModules;
70 public static «YangModuleInfo.importedName» getInstance() {
74 «classBody(module, MODULE_INFO_CLASS_NAME)»
78 package «packageName» ;
84 def String generateModelProvider() {
86 package «packageName»;
88 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
90 public «YangModuleInfo.name» getModuleInfo() {
91 return «MODULE_INFO_CLASS_NAME».getInstance();
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»<>();
103 «IF !m.imports.empty»
104 «FOR imp : m.imports»
105 «val name = imp.moduleName»
106 «val rev = imp.revision»
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)»
115 set.add(«getRootPackageName(sorted.lastEntry().value.QNameModule)».«MODULE_INFO_CLASS_NAME».getInstance());
117 set.add(«getRootPackageName((ctx.findModuleByName(name, rev).QNameModule))».«MODULE_INFO_CLASS_NAME».getInstance());
121 «IF !m.submodules.empty»
122 «FOR submodule : m.submodules»
123 set.add(«getClassName(submodule.name)»Info.getInstance());
126 «IF m.imports.empty && m.submodules.empty»
127 importedModules = «Collections.importedName».emptySet();
129 importedModules = «ImmutableSet.importedName».copyOf(set);
132 «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
133 if (stream == null) {
134 throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
138 } catch («IOException.importedName» e) {
139 // Resource leak, but there is nothing we can do
144 public «String.importedName» getName() {
149 public «String.importedName» getRevision() {
154 public «String.importedName» getNamespace() {
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");
168 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
169 return importedModules;
173 public «String.importedName» toString() {
174 «StringBuilder.importedName» sb = new «StringBuilder.importedName»(this.getClass().getCanonicalName());
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);
182 return sb.toString();
189 def getSourcePath() {
190 return "/" + module.moduleSourcePath.replace(java.io.File.separatorChar, '/')
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»;
203 final protected def importedName(Class<?> cls) {
204 val Type intype = Types.typeForClass(cls)
205 putTypeIntoImports(intype);
206 getExplicitType(intype)
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()) {
215 if (!importMap.containsKey(typeName)) {
216 importMap.put(typeName, typePackageName);
218 if (type instanceof ParameterizedType) {
219 val Type[] params = type.getActualTypeArguments()
220 if (params != null) {
221 for (Type param : params) {
222 putTypeIntoImports(param);
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 addActualTypeParameters(builder, type);
236 if (builder.toString().equals("Void")) {
240 builder = new StringBuilder();
241 if (typePackageName.startsWith("java.lang")) {
242 builder.append(type.getName());
244 if (!typePackageName.isEmpty()) {
245 builder.append(typePackageName + Constants.DOT + type.getName());
247 builder.append(type.getName());
250 if (type.equals(Types.voidType())) {
253 addActualTypeParameters(builder, type);
255 return builder.toString();
258 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
259 if (type instanceof ParameterizedType) {
260 val Type[] pTypes = type.getActualTypeArguments();
262 builder.append(getParameters(pTypes));
268 final def String getParameters(Type[] pTypes) {
269 if (pTypes == null || pTypes.length == 0) {
272 val StringBuilder builder = new StringBuilder();
275 for (pType : pTypes) {
276 val Type t = pTypes.get(i)
278 var String separator = ",";
279 if (i == (pTypes.length - 1)) {
283 var String wildcardParam = "";
284 if (t.equals(Types.voidType())) {
285 builder.append("java.lang.Void" + separator);
288 if (t instanceof WildcardType) {
289 wildcardParam = "? extends ";
292 builder.append(wildcardParam + getExplicitType(t) + separator);
296 return builder.toString();
299 private def generateSubInfo(Module module) '''
300 «FOR submodule : module.submodules»
301 private static final class «getClassName(submodule.name)»Info implements «YangModuleInfo.importedName» {
303 private static final «YangModuleInfo.importedName» INSTANCE = new «getClassName(submodule.name)»Info();
305 private final «String.importedName» name = "«submodule.name»";
306 private final «String.importedName» namespace = "«submodule.namespace.toString»";
307 «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
308 private final «String.importedName» revision = "«df.format(submodule.revision)»";
309 private final «String.importedName» resourcePath = "/«submodule.moduleSourcePath.replace(java.io.File.separatorChar, '/')»";
311 private final «Set.importedName»<YangModuleInfo> importedModules;
313 public static «YangModuleInfo.importedName» getInstance() {
317 «classBody(submodule, getClassName(submodule.name + "Info"))»