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 extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getClassName
11 import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getRootPackageName
12 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME
13 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_CLASS_NAME
14 import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_QNAMEOF_METHOD_NAME
16 import com.google.common.base.Preconditions
17 import com.google.common.collect.ImmutableSet
18 import java.util.Comparator
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 {
45 static val Comparator<Optional<Revision>> REVISION_COMPARATOR =
46 [ Optional<Revision> first, Optional<Revision> second | Revision.compare(first, second) ]
50 val Map<String, String> importMap = new LinkedHashMap()
51 val Function<Module, Optional<String>> moduleFilePathResolver
54 val String packageName
57 val String modelBindingProviderName
59 new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
60 Preconditions.checkArgument(module !== null, "Module must not be null.")
63 this.moduleFilePathResolver = moduleFilePathResolver
64 packageName = module.QNameModule.rootPackageName;
65 modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
68 def String generate() {
69 val Set<Module> submodules = new HashSet
70 collectSubmodules(submodules, module)
73 public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
74 «val rev = module.revision»
75 private static final «QName.importedName» NAME = «QName.importedName».create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
76 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
78 private final «ImmutableSet.importedName»<«YangModuleInfo.importedName»> importedModules;
80 public static «YangModuleInfo.importedName» getInstance() {
84 public static «QName.importedName» «MODULE_INFO_QNAMEOF_METHOD_NAME»(final «String.importedName» localName) {
85 return «QName.importedName».create(NAME, localName).intern();
88 «classBody(module, MODULE_INFO_CLASS_NAME, submodules)»
92 package «packageName»;
100 def String generateModelProvider() {
102 package «packageName»;
104 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
105 @«Override.importedName»
106 public «YangModuleInfo.name» getModuleInfo() {
107 return «MODULE_INFO_CLASS_NAME».getInstance();
114 private static def void collectSubmodules(Set<Module> dest, Module module) {
115 for (Module submodule : module.submodules) {
116 if (dest.add(submodule)) {
117 collectSubmodules(dest, submodule)
122 private def CharSequence classBody(Module m, String className, Set<Module> submodules) '''
123 private «className»() {
124 «IF !m.imports.empty || !submodules.empty»
125 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
127 «IF !m.imports.empty»
128 «FOR imp : m.imports»
129 «val name = imp.moduleName»
130 «val rev = imp.revision»
132 «val Set<Module> modules = ctx.modules»
133 «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap(REVISION_COMPARATOR)»
134 «FOR module : modules»
135 «IF module.name.equals(name)»
136 «sorted.put(module.revision, module)»
139 set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
141 set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
145 «FOR submodule : submodules»
146 set.add(«submodule.name.className»Info.getInstance());
148 «IF m.imports.empty && submodules.empty»
149 importedModules = «ImmutableSet.importedName».of();
151 importedModules = «ImmutableSet.importedName».copyOf(set);
155 @«Override.importedName»
156 public «QName.importedName» getName() {
160 @«Override.importedName»
161 protected «String.importedName» resourceName() {
162 return "«sourcePath(m)»";
165 @«Override.importedName»
166 public «ImmutableSet.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
167 return importedModules;
169 «generateSubInfo(submodules)»
172 private def sourcePath(Module module) {
173 val opt = moduleFilePathResolver.apply(module)
174 Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
178 private def imports() '''
179 «IF !importMap.empty»
180 «FOR entry : importMap.entrySet»
181 «IF entry.value != module.QNameModule.rootPackageName»
182 import «entry.value».«entry.key»;
188 final protected def importedName(Class<?> cls) {
189 val Type intype = Types.typeForClass(cls)
190 putTypeIntoImports(intype)
194 final def void putTypeIntoImports(Type type) {
195 val String typeName = type.name
196 val String typePackageName = type.packageName
197 if (typePackageName.startsWith("java.lang") || typePackageName.empty) {
200 if (!importMap.containsKey(typeName)) {
201 importMap.put(typeName, typePackageName)
203 if (type instanceof ParameterizedType) {
204 val Type[] params = type.actualTypeArguments
205 if (params !== null) {
206 for (Type param : params) {
207 putTypeIntoImports(param)
213 final def String getExplicitType(Type type) {
214 val String typePackageName = type.packageName
215 val String typeName = type.name
216 val String importedPackageName = importMap.get(typeName)
217 var StringBuilder builder
218 if (typePackageName.equals(importedPackageName)) {
219 builder = new StringBuilder(typeName)
220 if (builder.toString().equals("Void")) {
223 addActualTypeParameters(builder, type)
225 if (type.equals(Types.voidType())) {
228 builder = new StringBuilder()
229 if (!typePackageName.empty) {
230 builder.append(typePackageName).append(Constants.DOT).append(typeName)
232 builder.append(typeName)
234 addActualTypeParameters(builder, type)
236 return builder.toString()
239 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
240 if (type instanceof ParameterizedType) {
241 val Type[] pTypes = type.actualTypeArguments
242 builder.append('<').append(getParameters(pTypes)).append('>')
247 final def String getParameters(Type[] pTypes) {
248 if (pTypes === null || pTypes.length == 0) {
251 val StringBuilder builder = new StringBuilder()
254 for (pType : pTypes) {
255 val Type t = pTypes.get(i)
257 var String separator = ","
258 if (i == (pTypes.length - 1)) {
262 var String wildcardParam = ""
263 if (t.equals(Types.voidType())) {
264 builder.append("java.lang.Void").append(separator)
267 if (t instanceof WildcardType) {
268 wildcardParam = "? extends "
271 builder.append(wildcardParam).append(t.explicitType).append(separator)
275 return builder.toString()
278 private def generateSubInfo(Set<Module> submodules) '''
279 «FOR submodule : submodules»
280 «val className = submodule.name.className»
282 private static final class «className»Info extends «ResourceYangModuleInfo.importedName» {
283 «val rev = submodule.revision»
284 private final «QName.importedName» NAME = «QName.importedName».create("«
285 submodule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern();
286 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
288 private final «ImmutableSet.importedName»<YangModuleInfo> importedModules;
290 public static «YangModuleInfo.importedName» getInstance() {
294 «classBody(submodule, className + "Info", ImmutableSet.of)»