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.BindingGeneratorUtil
24 import org.opendaylight.yangtools.binding.generator.util.Types
25 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType
26 import org.opendaylight.yangtools.sal.binding.model.api.Type
27 import org.opendaylight.yangtools.sal.binding.model.api.WildcardType
28 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
29 import org.opendaylight.yangtools.yang.model.api.Module
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext
32 import com.google.common.collect.ImmutableSet
33 import static org.opendaylight.yangtools.yang.binding.BindingMapping.*
34 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
35 import com.google.common.base.Preconditions
36 import org.opendaylight.yangtools.yang.binding.BindingMapping
38 class YangModuleInfoTemplate {
42 val Map<String, String> importMap = new LinkedHashMap()
45 val String packageName;
48 val String modelBindingProviderName;
50 new(Module module, SchemaContext ctx) {
51 Preconditions.checkArgument(module != null, "Module must not be null.");
54 _packageName = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
55 _modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»''';
58 def String generate() {
60 public final class «MODULE_INFO_CLASS_NAME» implements «YangModuleInfo.importedName» {
62 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
64 private final «String.importedName» name = "«module.name»";
65 private final «String.importedName» namespace = "«module.namespace.toString»";
66 «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
67 private final «String.importedName» revision = "«df.format(module.revision)»";
68 private final «String.importedName» resourcePath = "«sourcePath»";
70 private final «Set.importedName»<YangModuleInfo> importedModules;
72 public static «YangModuleInfo.importedName» getInstance() {
76 «classBody(module, MODULE_INFO_CLASS_NAME)»
80 package «packageName» ;
86 def String generateModelProvider() {
88 package «packageName»;
90 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
92 public «YangModuleInfo.name» getModuleInfo() {
93 return «MODULE_INFO_CLASS_NAME».getInstance();
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»<>();
105 «IF !m.imports.empty»
106 «FOR imp : m.imports»
107 «val name = imp.moduleName»
108 «val rev = imp.revision»
110 «val Set<Module> modules = ctx.modules»
111 «val TreeMap<Date, Module> sorted = new TreeMap()»
112 «FOR module : modules»
113 «IF module.name.equals(name)»
114 «sorted.put(module.revision, module)»
117 set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(sorted.lastEntry().value)».«MODULE_INFO_CLASS_NAME».getInstance());
119 set.add(«BindingGeneratorUtil.moduleNamespaceToPackageName(ctx.findModuleByName(name, rev))».«MODULE_INFO_CLASS_NAME».getInstance());
123 «IF !m.submodules.empty»
124 «FOR submodule : m.submodules»
125 set.add(«BindingMapping.getClassName(submodule.name)»Info.getInstance());
128 «IF m.imports.empty && m.submodules.empty»
129 importedModules = «Collections.importedName».emptySet();
131 importedModules = «ImmutableSet.importedName».copyOf(set);
134 «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
135 if (stream == null) {
136 throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
140 } catch («IOException.importedName» e) {
141 // Resource leak, but there is nothing we can do
146 public «String.importedName» getName() {
151 public «String.importedName» getRevision() {
156 public «String.importedName» getNamespace() {
161 public «InputStream.importedName» getModuleSourceStream() throws IOException {
162 «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath);
163 if (stream == null) {
164 throw new «IOException.importedName»("Resource " + resourcePath + " is missing");
170 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
171 return importedModules;
175 public «String.importedName» toString() {
176 «StringBuilder.importedName» sb = new «StringBuilder.importedName»(this.getClass().getCanonicalName());
178 sb.append("name = " + name);
179 sb.append(", namespace = " + namespace);
180 sb.append(", revision = " + revision);
181 sb.append(", resourcePath = " + resourcePath);
182 sb.append(", imports = " + importedModules);
184 return sb.toString();
191 def getSourcePath() {
192 return "/" + module.moduleSourcePath.replace(java.io.File.separatorChar, '/')
195 private def imports() '''
196 «IF !importMap.empty»
197 «FOR entry : importMap.entrySet»
198 «IF entry.value != BindingGeneratorUtil.moduleNamespaceToPackageName(module)»
199 import «entry.value».«entry.key»;
205 final protected def importedName(Class<?> cls) {
206 val Type intype = Types.typeForClass(cls)
207 putTypeIntoImports(intype);
208 getExplicitType(intype)
211 final def void putTypeIntoImports(Type type) {
212 val String typeName = type.getName();
213 val String typePackageName = type.getPackageName();
214 if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
217 if (!importMap.containsKey(typeName)) {
218 importMap.put(typeName, typePackageName);
220 if (type instanceof ParameterizedType) {
221 val ParameterizedType paramType = (type as ParameterizedType)
222 val Type[] params = paramType.getActualTypeArguments()
223 if (params != null) {
224 for (Type param : params) {
225 putTypeIntoImports(param);
231 final def String getExplicitType(Type type) {
232 val String typePackageName = type.getPackageName();
233 val String typeName = type.getName();
234 val String importedPackageName = importMap.get(typeName);
235 var StringBuilder builder;
236 if (typePackageName.equals(importedPackageName)) {
237 builder = new StringBuilder(type.getName());
238 addActualTypeParameters(builder, type);
239 if (builder.toString().equals("Void")) {
243 builder = new StringBuilder();
244 if (typePackageName.startsWith("java.lang")) {
245 builder.append(type.getName());
247 if (!typePackageName.isEmpty()) {
248 builder.append(typePackageName + Constants.DOT + type.getName());
250 builder.append(type.getName());
253 if (type.equals(Types.voidType())) {
256 addActualTypeParameters(builder, type);
258 return builder.toString();
261 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
262 if (type instanceof ParameterizedType) {
263 val ParameterizedType pType = (type as ParameterizedType)
264 val Type[] pTypes = pType.getActualTypeArguments();
266 builder.append(getParameters(pTypes));
272 final def String getParameters(Type[] pTypes) {
273 if (pTypes == null || pTypes.length == 0) {
276 val StringBuilder builder = new StringBuilder();
279 for (pType : pTypes) {
280 val Type t = pTypes.get(i)
282 var String separator = ",";
283 if (i == (pTypes.length - 1)) {
287 var String wildcardParam = "";
288 if (t.equals(Types.voidType())) {
289 builder.append("java.lang.Void" + separator);
292 if (t instanceof WildcardType) {
293 wildcardParam = "? extends ";
296 builder.append(wildcardParam + getExplicitType(t) + separator);
300 return builder.toString();
303 private def generateSubInfo(Module module) '''
304 «FOR submodule : module.submodules»
305 private static final class «BindingMapping.getClassName(submodule.name)»Info implements «YangModuleInfo.importedName» {
307 private static final «YangModuleInfo.importedName» INSTANCE = new «BindingMapping.getClassName(submodule.name)»Info();
309 private final «String.importedName» name = "«submodule.name»";
310 private final «String.importedName» namespace = "«submodule.namespace.toString»";
311 «val DateFormat df = new SimpleDateFormat("yyyy-MM-dd")»
312 private final «String.importedName» revision = "«df.format(submodule.revision)»";
313 private final «String.importedName» resourcePath = "/«submodule.moduleSourcePath.replace(java.io.File.separatorChar, '/')»";
315 private final «Set.importedName»<YangModuleInfo> importedModules;
317 public static «YangModuleInfo.importedName» getInstance() {
321 «classBody(submodule, BindingMapping.getClassName(submodule.name + "Info"))»