--- /dev/null
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.binding2.java.api.generator.renderers;
+
+import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODEL_BINDING_PROVIDER_CLASS_NAME;
+import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName;
+
+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.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import org.opendaylight.mdsal.binding2.generator.util.Types;
+import org.opendaylight.mdsal.binding2.model.api.ParameterizedType;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.WildcardType;
+import org.opendaylight.mdsal.binding2.spec.YangModelBindingProvider;
+import org.opendaylight.mdsal.binding2.spec.YangModuleInfo;
+import org.opendaylight.mdsal.binding2.txt.modelProviderTemplate;
+import org.opendaylight.mdsal.binding2.txt.yangModuleInfoTemplate;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class YangModuleInfoTemplateRenderer {
+
+ private final Module module;
+ private final SchemaContext ctx;
+ private final Map<String, String> importMap = new HashMap<>();
+ private final String packageName;
+ private final String modelBindingProviderName;
+
+ public YangModuleInfoTemplateRenderer(final Module module, final SchemaContext ctx) {
+
+ Preconditions.checkArgument(module != null, "Module must not be null.");
+ this.module = module;
+ this.ctx = ctx;
+ this.packageName = getRootPackageName(module);
+
+ final StringBuilder sb = new StringBuilder();
+ sb.append(packageName)
+ .append('.')
+ .append(MODEL_BINDING_PROVIDER_CLASS_NAME);
+ this.modelBindingProviderName = sb.toString();
+ }
+
+ protected String body() {
+ /**
+ * list of all imported names for template
+ */
+ final Map<String, String> importedNames = new HashMap<>();
+
+ importedNames.put("string", importedName(String.class));
+ importedNames.put("stringBuilder", importedName(StringBuilder.class));
+ importedNames.put("set", importedName(Set.class));
+ importedNames.put("hashSet", importedName(HashSet.class));
+ importedNames.put("collections", importedName(Collections.class));
+ importedNames.put("immutableSet", importedName(ImmutableSet.class));
+ importedNames.put("inputStream", importedName(InputStream.class));
+ importedNames.put("iOException", importedName(IOException.class));
+ importedNames.put("yangModuleInfo", importedName(YangModuleInfo.class));
+
+ return yangModuleInfoTemplate.render(module, ctx, importedNames).body();
+ }
+
+ /**
+ * builds template
+ * @return generated final template
+ */
+ public String generateTemplate() {
+ final StringBuilder sb = new StringBuilder();
+ /* body must be filled before imports method call */
+ final String templateBody = body();
+ sb.append("package ")
+ .append(packageName)
+ .append(";\n")
+ .append(imports())
+ .append(templateBody);
+ return sb.toString();
+ }
+
+ public String generateModelProvider() {
+ return modelProviderTemplate.render(packageName, YangModelBindingProvider.class.getName(), YangModuleInfo.class
+ .getName()).body();
+ }
+
+ /**
+ * walks through map of imports
+ * @return string of imports for template
+ */
+ private String imports() {
+ final StringBuilder sb = new StringBuilder();
+ for (Map.Entry<String, String> entry : importMap.entrySet()) {
+ if (!getRootPackageName(module).equals(entry.getValue())) {
+ sb.append("import ")
+ .append(entry.getValue())
+ .append('.')
+ .append(entry.getKey())
+ .append(";\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ private String importedName(final Class<?> cls) {
+ final Type inType = Types.typeForClass(cls);
+ putTypeIntoImports(inType);
+ return getExplicitType(inType);
+ }
+
+ private void putTypeIntoImports(final Type type) {
+ final String typeName = type.getName();
+ final String typePackageName = type.getPackageName();
+ if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
+ return;
+ }
+ if (!importMap.containsKey(typeName)) {
+ importMap.put(typeName, typePackageName);
+ }
+ if (type instanceof ParameterizedType) {
+ final Type[] params = ((ParameterizedType) type).getActualTypeArguments();
+ if (params != null) {
+ for (Type param : params) {
+ putTypeIntoImports(param);
+ }
+ }
+ }
+ }
+
+ private String getExplicitType(final Type type) {
+ final String typePackageName = type.getPackageName();
+ final String typeName = type.getName();
+ final String importedPackageName = importMap.get(typeName);
+ final StringBuilder sb;
+ if (typePackageName.equals(importedPackageName)) {
+ sb = new StringBuilder(type.getName());
+ if (sb.toString().equals("Void")) {
+ return "void";
+ }
+ addActualTypeParameters(sb, type);
+ } else {
+ if (type.equals(Types.voidType())) {
+ return "void";
+ }
+ sb = new StringBuilder();
+ if (!typePackageName.isEmpty()) {
+ sb.append(typePackageName)
+ .append('.')
+ .append(type.getName());
+ } else {
+ sb.append(type.getName());
+ }
+ addActualTypeParameters(sb, type);
+ }
+ return sb.toString();
+ }
+
+ private StringBuilder addActualTypeParameters(final StringBuilder sb, final Type type) {
+ if (type instanceof ParameterizedType) {
+ final Type[] pTypes = ((ParameterizedType) type).getActualTypeArguments();
+ sb.append('<');
+ sb.append(getParameters(pTypes));
+ sb.append('>');
+ }
+ return sb;
+ }
+
+ private String getParameters(final Type[] pTypes) {
+ if (pTypes == null || pTypes.length == 0) {
+ return "?";
+ }
+ final StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (Type pType : pTypes) {
+ final Type type = pTypes[i];
+ String separator = ",";
+ if (i == (pTypes.length - 1)) {
+ separator = "";
+ }
+ String wildcardParam = "";
+ if (type.equals(Types.voidType())) {
+ sb.append("java.lang.Void" + separator);
+ } else {
+ if (type instanceof WildcardType) {
+ wildcardParam = "? extends ";
+ }
+ sb.append(wildcardParam + getExplicitType(type) + separator);
+ i = i + 1;
+ }
+ }
+ return sb.toString();
+ }
+
+ public static Module getSortedQName(final Set<Module> modules, final String name) {
+ final TreeMap<Date, Module> sorted = new TreeMap<>();
+ for (Module module : modules) {
+ if (name.equals(module.getName())) {
+ sorted.put(module.getRevision(), module);
+ }
+ }
+ return sorted.lastEntry().getValue();
+ }
+}
\ No newline at end of file
--- /dev/null
+@*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *@
+
+@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getClassName
+@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName
+@import org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODULE_INFO_CLASS_NAME
+@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.getFormattedRevision
+@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.getSourcePath
+@import org.opendaylight.mdsal.binding2.java.api.generator.renderers.YangModuleInfoTemplateRenderer.getSortedQName
+@import org.opendaylight.yangtools.yang.model.api.Module
+@import org.opendaylight.yangtools.yang.model.api.SchemaContext
+
+@(module: Module, ctx: SchemaContext, importedNames: Map[String, String])
+@if(module != null && ctx != null) {
+public final class @{MODULE_INFO_CLASS_NAME} implements @{importedNames.get("yangModuleInfo")} {
+
+ private static final @{importedNames.get("yangModuleInfo")} INSTANCE = new @{MODULE_INFO_CLASS_NAME}();
+
+ private final @{importedNames.get("string")} name = "@{module.getName}";
+ private final @{importedNames.get("string")} namespace = "@{module.getNamespace.toString}";
+ private final @{importedNames.get("string")} revision = "@{getFormattedRevision(module.getRevision)}";
+ private final @{importedNames.get("string")} resourcePath = "@{getSourcePath(module)}";
+ private final @{importedNames.get("set")}<YangModuleInfo> importedModules;
+
+ public static @{importedNames.get("yangModuleInfo")} getInstance() {
+ return INSTANCE;
+ }
+
+ @{classBody(module, MODULE_INFO_CLASS_NAME)}
+}
+}
+
+@generateSubInfo(module: Module) = {
+@for(submodule <- module.getSubmodules) {
+ private static final class @{getClassName(submodule.getName)}Info implements @{importedNames.get("yangModuleInfo")} {
+
+ private static final @{importedNames.get("yangModuleInfo")} INSTANCE = new @{getClassName(submodule.getName)}Info();
+
+ private final @{importedNames.get("string")} name = "@{submodule.getName}";
+ private final @{importedNames.get("string")} namespace = "@{submodule.getNamespace.toString}";
+ private final @{importedNames.get("string")} revision = "@{getFormattedRevision(submodule.getRevision)}";
+ private final @{importedNames.get("string")} resourcePath = "@{getSourcePath(submodule)}";
+ private final @{importedNames.get("set")}<YangModuleInfo> importedModules;
+
+ public static @{importedNames.get("yangModuleInfo")} getInstance() {
+ return INSTANCE;
+ }
+
+ @{classBody(submodule, getClassName(submodule.getName + "Info"))}
+ }
+}
+}
+
+@classBody(module: Module, className: String) = {
+ private @{className}() {
+ @if(!module.getImports.isEmpty || !module.getSubmodules.isEmpty) {
+ @{importedNames.get("set")}<@{importedNames.get("yangModuleInfo")}> set = new @{importedNames.get("hashSet")}<>();
+ }
+ @if(!module.getImports.isEmpty) {
+ @for(moduleImport <- module.getImports) {
+ @if(moduleImport.getRevision == null) {
+ set.add(@{getRootPackageName(getSortedQName(ctx.getModules, moduleImport.getModuleName))}.@{MODULE_INFO_CLASS_NAME}.getInstance());
+ } else {
+ set.add(@{getRootPackageName(ctx.findModuleByName(moduleImport.getModuleName, moduleImport.getRevision))}.@{MODULE_INFO_CLASS_NAME}.getInstance());
+ }
+ }
+ }
+ @if(!module.getSubmodules.isEmpty) {
+ @for(submodule <- module.getSubmodules) {
+ set.add(@{getClassName(submodule.getName)}Info.getInstance());
+ }
+ }
+ @if(!module.getImports.isEmpty && !module.getSubmodules.isEmpty) {
+ importedModules = @{importedNames.get("collections")}.emptySet();
+ } else {
+ importedModules = @{importedNames.get("immutableSet")}.copyOf(set);
+ }
+
+ @{importedNames.get("inputStream")} stream = @{MODULE_INFO_CLASS_NAME}.class.getResourceAsStream(resourcePath);
+ if (stream == null) {
+ throw new IllegalStateException("Resource '" + resourcePath + "' is missing");
+ }
+ try {
+ stream.close();
+ } catch (@{importedNames.get("iOException")} e) {
+ // Resource leak, but there is nothing we can do
+ }
+ }
+
+ @@Override
+ public @{importedNames.get("string")} getName() {
+ return name;
+ }
+
+ @@Override
+ public @{importedNames.get("string")} getRevision() {
+ return revision;
+ }
+
+ @@Override
+ public @{importedNames.get("string")} getNamespace() {
+ return namespace;
+ }
+
+ @@Override
+ public @{importedNames.get("inputStream")} getModuleSourceStream() throws IOException {
+ @{importedNames.get("inputStream")} stream = @{MODULE_INFO_CLASS_NAME}.class.getResourceAsStream(resourcePath);
+ if (stream == null) {
+ throw new @{importedNames.get("iOException")}("Resource " + resourcePath + " is missing");
+ }
+ return stream;
+ }
+
+ @@Override
+ public @{importedNames.get("set")}<@{importedNames.get("YangModuleInfo")}> getImportedModules() {
+ return importedModules;
+ }
+
+ @@Override
+ public @{importedNames.get("string")} toString() {
+ @{importedNames.get("stringBuilder")} sb = new @{importedNames.get("stringBuilder")}(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(module)}
+}
\ No newline at end of file