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.opendaylight.mdsal.binding.model.api.ParameterizedType
29 import org.opendaylight.mdsal.binding.model.api.Type
30 import org.opendaylight.mdsal.binding.model.api.WildcardType
31 import org.opendaylight.mdsal.binding.model.util.Types
32 import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo
33 import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider
34 import org.opendaylight.yangtools.yang.binding.YangModuleInfo
35 import org.opendaylight.yangtools.yang.common.QName
36 import org.opendaylight.yangtools.yang.common.Revision
37 import org.opendaylight.yangtools.yang.model.api.Module
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext
41 * Template for {@link YangModuleInfo} implementation for a particular module. Aside from fulfilling that contract,
42 * this class provides a static {@code createQName(String)} method, which is used by co-generated code to initialize
45 class YangModuleInfoTemplate {
46 static val Comparator<Optional<Revision>> REVISION_COMPARATOR =
47 [ Optional<Revision> first, Optional<Revision> second | Revision.compare(first, second) ]
51 val Map<String, String> importMap = new LinkedHashMap()
52 val Function<Module, Optional<String>> moduleFilePathResolver
55 val String packageName
58 val String modelBindingProviderName
60 new(Module module, SchemaContext ctx, Function<Module, Optional<String>> moduleFilePathResolver) {
61 Preconditions.checkArgument(module !== null, "Module must not be null.")
64 this.moduleFilePathResolver = moduleFilePathResolver
65 packageName = module.QNameModule.rootPackageName;
66 modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''
69 def String generate() {
71 public final class «MODULE_INFO_CLASS_NAME» extends «ResourceYangModuleInfo.importedName» {
72 «val rev = module.revision»
73 private static final «QName.importedName» NAME = «QName.importedName».create("«module.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern();
74 private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»();
76 private final «Set.importedName»<«YangModuleInfo.importedName»> importedModules;
78 public static «YangModuleInfo.importedName» getInstance() {
82 public static «QName.importedName» «MODULE_INFO_QNAMEOF_METHOD_NAME»(final «String.importedName» localName) {
83 return «QName.importedName».create(NAME, localName).intern();
86 «classBody(module, MODULE_INFO_CLASS_NAME)»
90 package «packageName»;
98 def String generateModelProvider() {
100 package «packageName»;
102 public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» {
103 @«Override.importedName»
104 public «YangModuleInfo.name» getModuleInfo() {
105 return «MODULE_INFO_CLASS_NAME».getInstance();
112 private def CharSequence classBody(Module m, String className) '''
113 private «className»() {
114 «IF !m.imports.empty || !m.submodules.empty»
115 «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>();
117 «IF !m.imports.empty»
118 «FOR imp : m.imports»
119 «val name = imp.moduleName»
120 «val rev = imp.revision»
122 «val Set<Module> modules = ctx.modules»
123 «val TreeMap<Optional<Revision>, Module> sorted = new TreeMap(REVISION_COMPARATOR)»
124 «FOR module : modules»
125 «IF module.name.equals(name)»
126 «sorted.put(module.revision, module)»
129 set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
131 set.add(«(ctx.findModule(name, rev).get.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance());
135 «IF !m.submodules.empty»
136 «FOR submodule : m.submodules»
137 set.add(«submodule.name.className»Info.getInstance());
140 «IF m.imports.empty && m.submodules.empty»
141 importedModules = «Collections.importedName».emptySet();
143 importedModules = «ImmutableSet.importedName».copyOf(set);
147 @«Override.importedName»
148 public «QName.importedName» getName() {
152 @«Override.importedName»
153 protected «String.importedName» resourceName() {
154 return "«sourcePath(m)»";
157 @«Override.importedName»
158 public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() {
159 return importedModules;
166 private def sourcePath(Module module) {
167 val opt = moduleFilePathResolver.apply(module)
168 Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module)
172 private def imports() '''
173 «IF !importMap.empty»
174 «FOR entry : importMap.entrySet»
175 «IF entry.value != module.QNameModule.rootPackageName»
176 import «entry.value».«entry.key»;
182 final protected def importedName(Class<?> cls) {
183 val Type intype = Types.typeForClass(cls)
184 putTypeIntoImports(intype)
188 final def void putTypeIntoImports(Type type) {
189 val String typeName = type.name
190 val String typePackageName = type.packageName
191 if (typePackageName.startsWith("java.lang") || typePackageName.empty) {
194 if (!importMap.containsKey(typeName)) {
195 importMap.put(typeName, typePackageName)
197 if (type instanceof ParameterizedType) {
198 val Type[] params = type.actualTypeArguments
199 if (params !== null) {
200 for (Type param : params) {
201 putTypeIntoImports(param)
207 final def String getExplicitType(Type type) {
208 val String typePackageName = type.packageName
209 val String typeName = type.name
210 val String importedPackageName = importMap.get(typeName)
211 var StringBuilder builder
212 if (typePackageName.equals(importedPackageName)) {
213 builder = new StringBuilder(typeName)
214 if (builder.toString().equals("Void")) {
217 addActualTypeParameters(builder, type)
219 if (type.equals(Types.voidType())) {
222 builder = new StringBuilder()
223 if (!typePackageName.empty) {
224 builder.append(typePackageName).append(Constants.DOT).append(typeName)
226 builder.append(typeName)
228 addActualTypeParameters(builder, type)
230 return builder.toString()
233 final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) {
234 if (type instanceof ParameterizedType) {
235 val Type[] pTypes = type.actualTypeArguments
236 builder.append('<').append(getParameters(pTypes)).append('>')
241 final def String getParameters(Type[] pTypes) {
242 if (pTypes === null || pTypes.length == 0) {
245 val StringBuilder builder = new StringBuilder()
248 for (pType : pTypes) {
249 val Type t = pTypes.get(i)
251 var String separator = ","
252 if (i == (pTypes.length - 1)) {
256 var String wildcardParam = ""
257 if (t.equals(Types.voidType())) {
258 builder.append("java.lang.Void").append(separator)
261 if (t instanceof WildcardType) {
262 wildcardParam = "? extends "
265 builder.append(wildcardParam).append(t.explicitType).append(separator)
269 return builder.toString()
272 private def generateSubInfo(Module module) '''
273 «FOR submodule : module.submodules»
274 «val className = submodule.name.className»
275 private static final class «className»Info extends «ResourceYangModuleInfo.importedName» {
276 «val rev = submodule.revision»
277 private final «QName.importedName» NAME = «QName.importedName».create("«
278 submodule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern();
279 private static final «YangModuleInfo.importedName» INSTANCE = new «className»Info();
281 private final «Set.importedName»<YangModuleInfo> importedModules;
283 public static «YangModuleInfo.importedName» getInstance() {
287 «classBody(submodule, className + "Info")»