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 org.opendaylight.yangtools.yang.binding.BindingMapping.MODULE_INFO_QNAMEOF_METHOD_NAME
13 import static extension org.opendaylight.yangtools.yang.binding.BindingMapping.getClassName
14 import static extension org.opendaylight.yangtools.yang.binding.BindingMapping.getRootPackageName
16 import com.google.common.base.Preconditions
17 import com.google.common.collect.ImmutableSet
18 import java.util.Collections
19 import java.util.HashSet
20 import java.util.LinkedHashMap
22 import java.util.Optional
24 import java.util.TreeMap
25 import java.util.function.Function
26 import org.eclipse.xtend.lib.annotations.Accessors
27 import org.opendaylight.mdsal.binding.model.api.ParameterizedType
28 import org.opendaylight.mdsal.binding.model.api.Type
29 import org.opendaylight.mdsal.binding.model.api.WildcardType
30 import org.opendaylight.mdsal.binding.model.util.Types
31 import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo
32 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
33 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
34 import org.opendaylight.yangtools.yang.common.QName
35 import org.opendaylight.yangtools.yang.common.Revision
36 import org.opendaylight.yangtools.yang.model.api.Module
37 import org.opendaylight.yangtools.yang.model.api.SchemaContext
40 * Template for {@link YangModuleInfo} implementation for a particular module. Aside from fulfilling that contract,
41 * this class provides a static {@code createQName(String)} method, which is used by co-generated code to initialize
44 class YangModuleInfoTemplate {
48 val Map<String, String> importMap = new LinkedHashMap()
49 val Function<Module, Optional<String>> moduleFilePathResolver
52 val String packageName
55 val String modelBindingProviderName
57 new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
58 Preconditions.checkArgument(module !== null, "Module must not be null.")
61 this.moduleFilePathResolver = moduleFilePathResolver
62 packageName = module.QNameModule.rootPackageName;
63 modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
66 def String generate() {
68 public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
69 «val rev = module.revision»
70 private static final «QName.importedName» NAME = «QName.importedName».create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
71 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
73 private final «Set.importedName»<«YangModuleInfo.importedName»> importedModules;
75 public static «YangModuleInfo.importedName» getInstance() {
79 public static «QName.importedName» «MODULE_INFO_QNAMEOF_METHOD_NAME»(final «String.importedName» localName) {
80 return «QName.importedName».create(NAME, localName).intern();
83 «classBody(module, MODULE_INFO_CLASS_NAME)»
87 package «packageName»;
95 def String generateModelProvider() {
97 package «packageName»;
99 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
101 public «YangModuleInfo.name» getModuleInfo() {
102 return «MODULE_INFO_CLASS_NAME».getInstance();
109 private def CharSequence classBody(Module m, String className) '''
110 private «className»() {
111 «IF !m.imports.empty || !m.submodules.empty»
112 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
114 «IF !m.imports.empty»
115 «FOR imp : m.imports»
116 «val name = imp.moduleName»
117 «val rev = imp.revision»
119 «val Set<Module> modules = ctx.modules»
120 «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap()»
121 «FOR module : modules»
122 «IF module.name.equals(name)»
123 «sorted.put(module.revision, module)»
126 set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
128 set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
132 «IF !m.submodules.empty»
133 «FOR submodule : m.submodules»
134 set.add(«submodule.name.className»Info.getInstance());
137 «IF m.imports.empty && m.submodules.empty»
138 importedModules = «Collections.importedName».emptySet();
140 importedModules = «ImmutableSet.importedName».copyOf(set);
145 public «QName.importedName» getName() {
150 protected «String.importedName» resourceName() {
151 return "«sourcePath(m)»";
155 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
156 return importedModules;
163 private def sourcePath(Module module) {
164 val opt = moduleFilePathResolver.apply(module)
165 Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
169 private def imports() '''
170 «IF !importMap.empty»
171 «FOR entry : importMap.entrySet»
172 «IF entry.value != module.QNameModule.rootPackageName»
173 import «entry.value».«entry.key»;
179 final protected def importedName(Class<?> cls) {
180 val Type intype = Types.typeForClass(cls)
181 putTypeIntoImports(intype)
185 final def void putTypeIntoImports(Type type) {
186 val String typeName = type.name
187 val String typePackageName = type.packageName
188 if (typePackageName.startsWith("java.lang") || typePackageName.empty) {
191 if (!importMap.containsKey(typeName)) {
192 importMap.put(typeName, typePackageName)
194 if (type instanceof ParameterizedType) {
195 val Type[] params = type.actualTypeArguments
196 if (params !== null) {
197 for (Type param : params) {
198 putTypeIntoImports(param)
204 final def String getExplicitType(Type type) {
205 val String typePackageName = type.packageName
206 val String typeName = type.name
207 val String importedPackageName = importMap.get(typeName)
208 var StringBuilder builder
209 if (typePackageName.equals(importedPackageName)) {
210 builder = new StringBuilder(typeName)
211 if (builder.toString().equals("Void")) {
214 addActualTypeParameters(builder, type)
216 if (type.equals(Types.voidType())) {
219 builder = new StringBuilder()
220 if (!typePackageName.empty) {
221 builder.append(typePackageName).append(Constants.DOT).append(typeName)
223 builder.append(typeName)
225 addActualTypeParameters(builder, type)
227 return builder.toString()
230 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
231 if (type instanceof ParameterizedType) {
232 val Type[] pTypes = type.actualTypeArguments
233 builder.append('<').append(getParameters(pTypes)).append('>')
238 final def String getParameters(Type[] pTypes) {
239 if (pTypes === null || pTypes.length == 0) {
242 val StringBuilder builder = new StringBuilder()
245 for (pType : pTypes) {
246 val Type t = pTypes.get(i)
248 var String separator = ","
249 if (i == (pTypes.length - 1)) {
253 var String wildcardParam = ""
254 if (t.equals(Types.voidType())) {
255 builder.append("java.lang.Void").append(separator)
258 if (t instanceof WildcardType) {
259 wildcardParam = "? extends "
262 builder.append(wildcardParam).append(t.explicitType).append(separator)
266 return builder.toString()
269 private def generateSubInfo(Module module) '''
270 «FOR submodule : module.submodules»
271 «val className = submodule.name.className»
272 private static final class «className»Info extends «ResourceYangModuleInfo.importedName» {
273 «val rev = submodule.revision»
274 private final «QName.importedName» NAME = «QName.importedName».create("«
275 submodule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern();
276 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
278 private final «Set.importedName»<YangModuleInfo> importedModules;
280 public static «YangModuleInfo.importedName» getInstance() {
284 «classBody(submodule, className + "Info")»