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.Collections
19 import java.util.Comparator
20 import java.util.HashSet
21 import java.util.LinkedHashMap
23 import java.util.Optional
25 import java.util.TreeMap
26 import java.util.function.Function
27 import org.eclipse.xtend.lib.annotations.Accessors
28 import org.gaul.modernizer_maven_annotations.SuppressModernizer
29 import org.opendaylight.mdsal.binding.model.api.ParameterizedType
30 import org.opendaylight.mdsal.binding.model.api.Type
31 import org.opendaylight.mdsal.binding.model.api.WildcardType
32 import org.opendaylight.mdsal.binding.model.util.Types
33 import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo
34 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
35 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
36 import org.opendaylight.yangtools.yang.common.QName
37 import org.opendaylight.yangtools.yang.common.Revision
38 import org.opendaylight.yangtools.yang.model.api.Module
39 import org.opendaylight.yangtools.yang.model.api.SchemaContext
42 * Template for {@link YangModuleInfo} implementation for a particular module. Aside from fulfilling that contract,
43 * this class provides a static {@code createQName(String)} method, which is used by co-generated code to initialize
47 class YangModuleInfoTemplate {
48 static val Comparator<Optional<Revision>> REVISION_COMPARATOR =
49 [ Optional<Revision> first, Optional<Revision> second | Revision.compare(first, second) ]
53 val Map<String, String> importMap = new LinkedHashMap()
54 val Function<Module, Optional<String>> moduleFilePathResolver
57 val String packageName
60 val String modelBindingProviderName
62 new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
63 Preconditions.checkArgument(module !== null, "Module must not be null.")
66 this.moduleFilePathResolver = moduleFilePathResolver
67 packageName = module.QNameModule.rootPackageName;
68 modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
71 def String generate() {
72 val Set<Module> submodules = new HashSet
73 collectSubmodules(submodules, module)
76 public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
77 «val rev = module.revision»
78 private static final «QName.importedName» NAME = «QName.importedName».create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
79 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
81 private final «Set.importedName»<«YangModuleInfo.importedName»> importedModules;
83 public static «YangModuleInfo.importedName» getInstance() {
87 public static «QName.importedName» «MODULE_INFO_QNAMEOF_METHOD_NAME»(final «String.importedName» localName) {
88 return «QName.importedName».create(NAME, localName).intern();
91 «classBody(module, MODULE_INFO_CLASS_NAME, submodules)»
95 package «packageName»;
103 def String generateModelProvider() {
105 package «packageName»;
107 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
108 @«Override.importedName»
109 public «YangModuleInfo.name» getModuleInfo() {
110 return «MODULE_INFO_CLASS_NAME».getInstance();
117 private static def void collectSubmodules(Set<Module> dest, Module module) {
118 for (Module submodule : module.submodules) {
119 if (dest.add(submodule)) {
120 collectSubmodules(dest, submodule)
125 private def CharSequence classBody(Module m, String className, Set<Module> submodules) '''
126 private «className»() {
127 «IF !m.imports.empty || !submodules.empty»
128 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
130 «IF !m.imports.empty»
131 «FOR imp : m.imports»
132 «val name = imp.moduleName»
133 «val rev = imp.revision»
135 «val Set<Module> modules = ctx.modules»
136 «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap(REVISION_COMPARATOR)»
137 «FOR module : modules»
138 «IF module.name.equals(name)»
139 «sorted.put(module.revision, module)»
142 set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
144 set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
148 «FOR submodule : submodules»
149 set.add(«submodule.name.className»Info.getInstance());
151 «IF m.imports.empty && submodules.empty»
152 importedModules = «Collections.importedName».emptySet();
154 importedModules = «ImmutableSet.importedName».copyOf(set);
158 @«Override.importedName»
159 public «QName.importedName» getName() {
163 @«Override.importedName»
164 protected «String.importedName» resourceName() {
165 return "«sourcePath(m)»";
168 @«Override.importedName»
169 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
170 return importedModules;
172 «generateSubInfo(submodules)»
175 private def sourcePath(Module module) {
176 val opt = moduleFilePathResolver.apply(module)
177 Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
181 private def imports() '''
182 «IF !importMap.empty»
183 «FOR entry : importMap.entrySet»
184 «IF entry.value != module.QNameModule.rootPackageName»
185 import «entry.value».«entry.key»;
191 final protected def importedName(Class<?> cls) {
192 val Type intype = Types.typeForClass(cls)
193 putTypeIntoImports(intype)
197 final def void putTypeIntoImports(Type type) {
198 val String typeName = type.name
199 val String typePackageName = type.packageName
200 if (typePackageName.startsWith("java.lang") || typePackageName.empty) {
203 if (!importMap.containsKey(typeName)) {
204 importMap.put(typeName, typePackageName)
206 if (type instanceof ParameterizedType) {
207 val Type[] params = type.actualTypeArguments
208 if (params !== null) {
209 for (Type param : params) {
210 putTypeIntoImports(param)
216 final def String getExplicitType(Type type) {
217 val String typePackageName = type.packageName
218 val String typeName = type.name
219 val String importedPackageName = importMap.get(typeName)
220 var StringBuilder builder
221 if (typePackageName.equals(importedPackageName)) {
222 builder = new StringBuilder(typeName)
223 if (builder.toString().equals("Void")) {
226 addActualTypeParameters(builder, type)
228 if (type.equals(Types.voidType())) {
231 builder = new StringBuilder()
232 if (!typePackageName.empty) {
233 builder.append(typePackageName).append(Constants.DOT).append(typeName)
235 builder.append(typeName)
237 addActualTypeParameters(builder, type)
239 return builder.toString()
242 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
243 if (type instanceof ParameterizedType) {
244 val Type[] pTypes = type.actualTypeArguments
245 builder.append('<').append(getParameters(pTypes)).append('>')
250 final def String getParameters(Type[] pTypes) {
251 if (pTypes === null || pTypes.length == 0) {
254 val StringBuilder builder = new StringBuilder()
257 for (pType : pTypes) {
258 val Type t = pTypes.get(i)
260 var String separator = ","
261 if (i == (pTypes.length - 1)) {
265 var String wildcardParam = ""
266 if (t.equals(Types.voidType())) {
267 builder.append("java.lang.Void").append(separator)
270 if (t instanceof WildcardType) {
271 wildcardParam = "? extends "
274 builder.append(wildcardParam).append(t.explicitType).append(separator)
278 return builder.toString()
281 private def generateSubInfo(Set<Module> submodules) '''
282 «FOR submodule : submodules»
283 «val className = submodule.name.className»
285 private static final class «className»Info extends «ResourceYangModuleInfo.importedName» {
286 «val rev = submodule.revision»
287 private final «QName.importedName» NAME = «QName.importedName».create("«
288 submodule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern();
289 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
291 private final «Set.importedName»<YangModuleInfo> importedModules;
293 public static «YangModuleInfo.importedName» getInstance() {
297 «classBody(submodule, className + "Info", Collections.emptySet)»