X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-java-api-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fjava%2Fapi%2Fgenerator%2FYangModuleInfoTemplate.xtend;h=9bb9a6acb5f75def3f7246b214926329da7a9133;hb=163325d8770b579bb88151521c80efec9eee9bb5;hp=912434a76f1047b93de5d1adbde16f63d5a732e7;hpb=2feef137f8998d1355a029d43901074e74fa9b30;p=mdsal.git diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/YangModuleInfoTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/YangModuleInfoTemplate.xtend index 912434a76f..9bb9a6acb5 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/YangModuleInfoTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/YangModuleInfoTemplate.xtend @@ -7,322 +7,266 @@ */ package org.opendaylight.mdsal.binding.java.api.generator -import static org.opendaylight.yangtools.yang.binding.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME -import static org.opendaylight.yangtools.yang.binding.BindingMapping.MODULE_INFO_CLASS_NAME -import static org.opendaylight.yangtools.yang.binding.BindingMapping.getClassName -import static org.opendaylight.yangtools.yang.binding.BindingMapping.getRootPackageName +import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getClassName +import static extension org.opendaylight.mdsal.binding.spec.naming.BindingMapping.getRootPackageName +import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODEL_BINDING_PROVIDER_CLASS_NAME +import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_CLASS_NAME +import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_QNAMEOF_METHOD_NAME +import static org.opendaylight.mdsal.binding.spec.naming.BindingMapping.MODULE_INFO_YANGDATANAMEOF_METHOD_NAME import com.google.common.base.Preconditions import com.google.common.collect.ImmutableSet -import java.io.IOException -import java.io.InputStream -import java.util.Collections +import java.util.Comparator import java.util.HashSet -import java.util.LinkedHashMap -import java.util.Map import java.util.Optional import java.util.Set import java.util.TreeMap import java.util.function.Function import org.eclipse.xtend.lib.annotations.Accessors -import org.opendaylight.mdsal.binding.model.api.ParameterizedType -import org.opendaylight.mdsal.binding.model.api.Type -import org.opendaylight.mdsal.binding.model.api.WildcardType -import org.opendaylight.mdsal.binding.model.util.Types -import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider +import org.opendaylight.yangtools.rfc8040.model.api.YangDataSchemaNode import org.opendaylight.yangtools.yang.binding.YangModuleInfo -import org.opendaylight.yangtools.yang.model.api.Module -import org.opendaylight.yangtools.yang.model.api.SchemaContext import org.opendaylight.yangtools.yang.common.Revision +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext +import org.opendaylight.yangtools.yang.model.api.Module +import org.opendaylight.yangtools.yang.model.api.ModuleLike +import org.opendaylight.yangtools.yang.model.api.Submodule -class YangModuleInfoTemplate { +/** + * Template for {@link YangModuleInfo} implementation for a particular module. Aside from fulfilling that contract, + * this class provides a static {@code createQName(String)} method, which is used by co-generated code to initialize + * QNAME constants. + */ +final class YangModuleInfoTemplate { + static val Comparator> REVISION_COMPARATOR = + [ Optional first, Optional second | Revision.compare(first, second) ] + + // These are always imported. Note we need to import even java.lang members, as there can be conflicting definitions + // in our package + static val CORE_IMPORT_STR = ''' + import com.google.common.collect.ImmutableSet; + import java.lang.Override; + import java.lang.String; + import org.eclipse.jdt.annotation.NonNull; + import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo; + import org.opendaylight.yangtools.yang.binding.YangModuleInfo; + import org.opendaylight.yangtools.yang.common.QName; + ''' + static val EXT_IMPORT_STR = ''' + import com.google.common.collect.ImmutableSet; + import java.lang.Override; + import java.lang.String; + import java.util.HashSet; + import java.util.Set; + import org.eclipse.jdt.annotation.NonNull; + import org.opendaylight.yangtools.yang.binding.ResourceYangModuleInfo; + import org.opendaylight.yangtools.yang.binding.YangModuleInfo; + import org.opendaylight.yangtools.yang.common.QName; + ''' val Module module - val SchemaContext ctx - val Map importMap = new LinkedHashMap() - val Function> moduleFilePathResolver + val EffectiveModelContext ctx + val Function> moduleFilePathResolver + val boolean hasYangData + + var importedTypes = CORE_IMPORT_STR @Accessors - val String packageName; + val String packageName @Accessors - val String modelBindingProviderName; + val String modelBindingProviderName - new(Module module, SchemaContext ctx, Function> moduleFilePathResolver) { - Preconditions.checkArgument(module !== null, "Module must not be null."); + new(Module module, EffectiveModelContext ctx, Function> moduleFilePathResolver) { + Preconditions.checkArgument(module !== null, "Module must not be null.") this.module = module this.ctx = ctx this.moduleFilePathResolver = moduleFilePathResolver - packageName = getRootPackageName(module.getQNameModule()); - modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»'''; + packageName = module.QNameModule.rootPackageName; + modelBindingProviderName = '''«packageName».«MODEL_BINDING_PROVIDER_CLASS_NAME»''' + hasYangData = module.unknownSchemaNodes.stream.anyMatch([s | s instanceof YangDataSchemaNode]) } def String generate() { - val body = ''' - public final class «MODULE_INFO_CLASS_NAME» implements «YangModuleInfo.importedName» { - - private static final «YangModuleInfo.importedName» INSTANCE = new «MODULE_INFO_CLASS_NAME»(); - - private final «String.importedName» name = "«module.name»"; - private final «String.importedName» namespace = "«module.namespace.toString»"; - «IF module.revision.isPresent» - private final «String.importedName» revision = "«module.revision.get.toString»"; - «ELSE» - private final «String.importedName» revision = null; - «ENDIF» - private final «String.importedName» resourcePath = "«sourcePath(module)»"; + val Set submodules = new HashSet + collectSubmodules(submodules, module) - private final «Set.importedName» importedModules; - - public static «YangModuleInfo.importedName» getInstance() { + val body = ''' + /** + * The {@link ResourceYangModuleInfo} for {@code «module.name»} module. + */ + @«JavaFileTemplate.GENERATED»("mdsal-binding-generator") + public final class «MODULE_INFO_CLASS_NAME» extends ResourceYangModuleInfo { + «val rev = module.revision» + private static final @NonNull QName NAME = QName.create("«module.QNameModule.namespace.toString»", «IF rev.present»"«rev.get.toString»", «ENDIF»"«module.name»").intern(); + private static final @NonNull YangModuleInfo INSTANCE = new «MODULE_INFO_CLASS_NAME»(); + + private final @NonNull ImmutableSet importedModules; + + /** + * Return the singleton instance of this class. + * + * @return The singleton instance + */ + public static @NonNull YangModuleInfo getInstance() { return INSTANCE; } - «classBody(module, MODULE_INFO_CLASS_NAME)» + /** + * Create an interned {@link QName} with specified {@code localName} and namespace/revision of this + * module. + * + * @param localName local name + * @return A QName + * @throws NullPointerException if {@code localName} is {@code null} + * @throws IllegalArgumentException if {@code localName} is not a valid YANG identifier + */ + public static @NonNull QName «MODULE_INFO_QNAMEOF_METHOD_NAME»(final String localName) { + return QName.create(NAME, localName).intern(); + } + «IF hasYangData» + + /** + * Create an interned {@link YangDataName} with specified {@code templateName} and namespace/revision of + * this module. + * + * @param templateName template name + * @return A YangDataName + * @throws NullPointerException if {@code templateName} is {@code null} + * @throws IllegalArgumentException if {@code templateName} is empty + */ + public static @NonNull YangDataName «MODULE_INFO_YANGDATANAMEOF_METHOD_NAME»(final String templateName) { + return new YangDataName(NAME.getModule(), templateName).intern(); + } + «ENDIF» + + «classBody(module, MODULE_INFO_CLASS_NAME, submodules)» } ''' return ''' - package «packageName» ; - «imports» + package «packageName»; + + «importedTypes» + «IF hasYangData» + import org.opendaylight.yangtools.yang.common.YangDataName; + «ENDIF» + «body» '''.toString } - def String generateModelProvider() { - ''' - package «packageName»; + def String generateModelProvider() ''' + package «packageName»; + + import java.lang.Override; + import java.util.ServiceLoader; + import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider; + import org.opendaylight.yangtools.yang.binding.YangModuleInfo; + + /** + * The {@link YangModelBindingProvider} for {@code «module.name»} module. This class should not be used + * directly, but rather through {@link ServiceLoader}. + */ + @«JavaFileTemplate.GENERATED»("mdsal-binding-generator") + public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements YangModelBindingProvider { + /** + * Construct a new provider. + */ + public «MODEL_BINDING_PROVIDER_CLASS_NAME»() { + // No-op + } - public final class «MODEL_BINDING_PROVIDER_CLASS_NAME» implements «YangModelBindingProvider.name» { - @Override - public «YangModuleInfo.name» getModuleInfo() { - return «MODULE_INFO_CLASS_NAME».getInstance(); - } + @Override + public YangModuleInfo getModuleInfo() { + return «MODULE_INFO_CLASS_NAME».getInstance(); } - ''' + } + ''' + private static def void collectSubmodules(Set dest, ModuleLike module) { + for (Submodule submodule : module.submodules) { + if (dest.add(submodule)) { + collectSubmodules(dest, submodule) + } + } } - private def CharSequence classBody(Module m, String className) ''' + private def CharSequence classBody(ModuleLike m, String className, Set submodules) ''' private «className»() { - «IF !m.imports.empty || !m.submodules.empty» - «Set.importedName»<«YangModuleInfo.importedName»> set = new «HashSet.importedName»<>(); + «IF !m.imports.empty || !submodules.empty» + «extendImports» + Set set = new HashSet<>(); «ENDIF» «IF !m.imports.empty» «FOR imp : m.imports» - «val name = imp.moduleName» + «val name = imp.moduleName.localName» «val rev = imp.revision» «IF !rev.present» - «val Set modules = ctx.modules» - «val TreeMap, Module> sorted = new TreeMap()» - «FOR module : modules» - «IF module.name.equals(name)» + «val TreeMap, Module> sorted = new TreeMap(REVISION_COMPARATOR)» + «FOR module : ctx.modules» + «IF name.equals(module.name)» «sorted.put(module.revision, module)» «ENDIF» «ENDFOR» - set.add(«getRootPackageName(sorted.lastEntry().value.QNameModule)».«MODULE_INFO_CLASS_NAME».getInstance()); + set.add(«sorted.lastEntry().value.QNameModule.rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance()); «ELSE» - set.add(«getRootPackageName((ctx.findModule(name, rev).get.QNameModule))».«MODULE_INFO_CLASS_NAME».getInstance()); + set.add(«(ctx.findModule(name, rev).orElseThrow.QNameModule).rootPackageName».«MODULE_INFO_CLASS_NAME».getInstance()); «ENDIF» «ENDFOR» «ENDIF» - «IF !m.submodules.empty» - «FOR submodule : m.submodules» - set.add(«getClassName(submodule.name)»Info.getInstance()); - «ENDFOR» - «ENDIF» - «IF m.imports.empty && m.submodules.empty» - importedModules = «Collections.importedName».emptySet(); + «FOR submodule : submodules» + set.add(«submodule.name.className»Info.getInstance()); + «ENDFOR» + «IF m.imports.empty && submodules.empty» + importedModules = ImmutableSet.of(); «ELSE» - importedModules = «ImmutableSet.importedName».copyOf(set); + importedModules = ImmutableSet.copyOf(set); «ENDIF» - - «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath); - if (stream == null) { - throw new IllegalStateException("Resource '" + resourcePath + "' is missing"); - } - try { - stream.close(); - } catch («IOException.importedName» e) { - // Resource leak, but there is nothing we can do - } - } - - @Override - public «String.importedName» getName() { - return name; } @Override - public «String.importedName» getRevision() { - return revision; + public QName getName() { + return NAME; } @Override - public «String.importedName» getNamespace() { - return namespace; - } - - @Override - public «InputStream.importedName» getModuleSourceStream() throws IOException { - «InputStream.importedName» stream = «MODULE_INFO_CLASS_NAME».class.getResourceAsStream(resourcePath); - if (stream == null) { - throw new «IOException.importedName»("Resource " + resourcePath + " is missing"); - } - return stream; + protected String resourceName() { + return "«sourcePath(m)»"; } @Override - public «Set.importedName»<«YangModuleInfo.importedName»> getImportedModules() { + public ImmutableSet getImportedModules() { return importedModules; } - - @Override - public «String.importedName» toString() { - «StringBuilder.importedName» sb = new «StringBuilder.importedName»(this.getClass().getCanonicalName()); - sb.append("["); - sb.append("name = " + name); - sb.append(", namespace = " + namespace); - sb.append(", revision = " + revision); - sb.append(", resourcePath = " + resourcePath); - sb.append(", imports = " + importedModules); - sb.append("]"); - return sb.toString(); - } - - «generateSubInfo(m)» - + «generateSubInfo(submodules)» ''' - private def sourcePath(Module module) { + private def void extendImports() { + importedTypes = EXT_IMPORT_STR + } + + private def sourcePath(ModuleLike module) { val opt = moduleFilePathResolver.apply(module) Preconditions.checkState(opt.isPresent, "Module %s does not have a file path", module) return opt.get } - private def imports() ''' - «IF !importMap.empty» - «FOR entry : importMap.entrySet» - «IF entry.value != getRootPackageName(module.QNameModule)» - import «entry.value».«entry.key»; - «ENDIF» - «ENDFOR» - «ENDIF» - ''' - - final protected def importedName(Class cls) { - val Type intype = Types.typeForClass(cls) - putTypeIntoImports(intype); - getExplicitType(intype) - } - - final def void putTypeIntoImports(Type type) { - val String typeName = type.getName(); - val String typePackageName = type.getPackageName(); - if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) { - return; - } - if (!importMap.containsKey(typeName)) { - importMap.put(typeName, typePackageName); - } - if (type instanceof ParameterizedType) { - val Type[] params = type.getActualTypeArguments() - if (params !== null) { - for (Type param : params) { - putTypeIntoImports(param); - } - } - } - } - - final def String getExplicitType(Type type) { - val String typePackageName = type.getPackageName(); - val String typeName = type.getName(); - val String importedPackageName = importMap.get(typeName); - var StringBuilder builder; - if (typePackageName.equals(importedPackageName)) { - builder = new StringBuilder(type.getName()); - if (builder.toString().equals("Void")) { - return "void"; - } - addActualTypeParameters(builder, type); - } else { - if (type.equals(Types.voidType())) { - return "void"; - } - builder = new StringBuilder(); - if (!typePackageName.isEmpty()) { - builder.append(typePackageName + Constants.DOT + type.getName()); - } else { - builder.append(type.getName()); - } - addActualTypeParameters(builder, type); - } - return builder.toString(); - } - - final def StringBuilder addActualTypeParameters(StringBuilder builder, Type type) { - if (type instanceof ParameterizedType) { - val Type[] pTypes = type.getActualTypeArguments(); - builder.append('<'); - builder.append(getParameters(pTypes)); - builder.append('>'); - } - return builder; - } - - final def String getParameters(Type[] pTypes) { - if (pTypes === null || pTypes.length == 0) { - return "?"; - } - val StringBuilder builder = new StringBuilder(); - - var int i = 0; - for (pType : pTypes) { - val Type t = pTypes.get(i) - - var String separator = ","; - if (i == (pTypes.length - 1)) { - separator = ""; - } - - var String wildcardParam = ""; - if (t.equals(Types.voidType())) { - builder.append("java.lang.Void" + separator); - } else { - - if (t instanceof WildcardType) { - wildcardParam = "? extends "; - } - - builder.append(wildcardParam + getExplicitType(t) + separator); - i = i + 1 - } - } - return builder.toString(); - } - - private def generateSubInfo(Module module) ''' - «FOR submodule : module.submodules» - private static final class «getClassName(submodule.name)»Info implements «YangModuleInfo.importedName» { - - private static final «YangModuleInfo.importedName» INSTANCE = new «getClassName(submodule.name)»Info(); + private def generateSubInfo(Set submodules) ''' + «FOR submodule : submodules» + «val className = submodule.name.className» - private final «String.importedName» name = "«submodule.name»"; - private final «String.importedName» namespace = "«submodule.namespace.toString»"; - «IF submodule.revision.isPresent» - private final «String.importedName» revision = "«submodule.revision.get.toString»"; - «ELSE» - private final «String.importedName» revision = null; - «ENDIF» - private final «String.importedName» resourcePath = "«sourcePath(submodule)»"; + private static final class «className»Info extends ResourceYangModuleInfo { + «val rev = submodule.revision» + private final @NonNull QName NAME = QName.create("«submodule.QNameModule.namespace.toString»", « + IF rev.present»"«rev.get.toString»", «ENDIF»"«submodule.name»").intern(); + private static final @NonNull YangModuleInfo INSTANCE = new «className»Info(); - private final «Set.importedName» importedModules; + private final @NonNull ImmutableSet importedModules; - public static «YangModuleInfo.importedName» getInstance() { + public static @NonNull YangModuleInfo getInstance() { return INSTANCE; } - «classBody(submodule, getClassName(submodule.name + "Info"))» + «classBody(submodule, className + "Info", ImmutableSet.of)» } «ENDFOR» '''