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.mdsal.binding.java.api.generator
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
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
21 import java.util.Optional
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
38 class YangModuleInfoTemplate {
42 val Map<String, String> importMap = new LinkedHashMap()
43 val Function<Module, Optional<String>> moduleFilePathResolver
46 val String packageName
49 val String modelBindingProviderName
51 new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
52 Preconditions.checkArgument(module !== null, "Module must not be null.")
55 this.moduleFilePathResolver = moduleFilePathResolver
56 packageName = module.QNameModule.rootPackageName;
57 modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
60 def String generate() {
62 public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
64 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
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;
70 public static «YangModuleInfo.importedName» getInstance() {
74 «classBody(module, MODULE_INFO_CLASS_NAME)»
78 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<Optional<Revision>, Module> sorted = new TreeMap()»
112 «FOR module : modules»
113 «IF module.name.equals(name)»
114 «sorted.put(module.revision, module)»
117 set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
119 set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
123 «IF !m.submodules.empty»
124 «FOR submodule : m.submodules»
125 set.add(«submodule.name.className»Info.getInstance());
128 «IF m.imports.empty && m.submodules.empty»
129 importedModules = «Collections.importedName».emptySet();
131 importedModules = «ImmutableSet.importedName».copyOf(set);
136 public «QName.importedName» getName() {
141 protected «String.importedName» resourceName() {
142 return "«sourcePath(m)»";
146 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
147 return importedModules;
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)
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»;
170 final protected def importedName(Class<?> cls) {
171 val Type intype = Types.typeForClass(cls)
172 putTypeIntoImports(intype)
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) {
182 if (!importMap.containsKey(typeName)) {
183 importMap.put(typeName, typePackageName)
185 if (type instanceof ParameterizedType) {
186 val Type[] params = type.actualTypeArguments
187 if (params !== null) {
188 for (Type param : params) {
189 putTypeIntoImports(param)
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")) {
205 addActualTypeParameters(builder, type)
207 if (type.equals(Types.voidType())) {
210 builder = new StringBuilder()
211 if (!typePackageName.empty) {
212 builder.append(typePackageName).append(Constants.DOT).append(typeName)
214 builder.append(typeName)
216 addActualTypeParameters(builder, type)
218 return builder.toString()
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('>')
229 final def String getParameters(Type[] pTypes) {
230 if (pTypes === null || pTypes.length == 0) {
233 val StringBuilder builder = new StringBuilder()
236 for (pType : pTypes) {
237 val Type t = pTypes.get(i)
239 var String separator = ","
240 if (i == (pTypes.length - 1)) {
244 var String wildcardParam = ""
245 if (t.equals(Types.voidType())) {
246 builder.append("java.lang.Void").append(separator)
249 if (t instanceof WildcardType) {
250 wildcardParam = "? extends "
253 builder.append(wildcardParam).append(t.explicitType).append(separator)
257 return builder.toString()
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» {
265 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
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;
271 public static «YangModuleInfo.importedName» getInstance() {
275 «classBody(submodule, className + "Info")»