d297f45dc2ffce9bec1d81d9ce7136b85297cc9d
[mdsal.git] / binding2 / mdsal-binding2-java-api-generator / src / main / java / org / opendaylight / mdsal / binding2 / java / api / generator / renderers / YangModuleInfoTemplateRenderer.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.mdsal.binding2.java.api.generator.renderers;
10
11 import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.MODEL_BINDING_PROVIDER_CLASS_NAME;
12 import static org.opendaylight.mdsal.binding2.generator.util.Binding2Mapping.getRootPackageName;
13
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableSet;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TreeMap;
25 import org.opendaylight.mdsal.binding2.generator.util.Types;
26 import org.opendaylight.mdsal.binding2.model.api.ParameterizedType;
27 import org.opendaylight.mdsal.binding2.model.api.Type;
28 import org.opendaylight.mdsal.binding2.model.api.WildcardType;
29 import org.opendaylight.mdsal.binding2.spec.YangModelBindingProvider;
30 import org.opendaylight.mdsal.binding2.spec.YangModuleInfo;
31 import org.opendaylight.mdsal.binding2.txt.modelProviderTemplate;
32 import org.opendaylight.mdsal.binding2.txt.yangModuleInfoTemplate;
33 import org.opendaylight.yangtools.yang.model.api.Module;
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35
36 public class YangModuleInfoTemplateRenderer {
37
38     private final Module module;
39     private final SchemaContext ctx;
40     private final Map<String, String> importMap = new HashMap<>();
41     private final String packageName;
42     private final String modelBindingProviderName;
43
44     public YangModuleInfoTemplateRenderer(final Module module, final SchemaContext ctx) {
45
46         Preconditions.checkArgument(module != null, "Module must not be null.");
47         this.module = module;
48         this.ctx = ctx;
49         this.packageName = getRootPackageName(module);
50
51         final StringBuilder sb = new StringBuilder();
52         sb.append(packageName)
53             .append('.')
54             .append(MODEL_BINDING_PROVIDER_CLASS_NAME);
55         this.modelBindingProviderName = sb.toString();
56     }
57
58     protected String body() {
59         /**
60          * list of all imported names for template
61          */
62         final Map<String, String> importedNames = new HashMap<>();
63
64         importedNames.put("string", importedName(String.class));
65         importedNames.put("stringBuilder", importedName(StringBuilder.class));
66         importedNames.put("set", importedName(Set.class));
67         importedNames.put("hashSet", importedName(HashSet.class));
68         importedNames.put("collections", importedName(Collections.class));
69         importedNames.put("immutableSet", importedName(ImmutableSet.class));
70         importedNames.put("inputStream", importedName(InputStream.class));
71         importedNames.put("iOException", importedName(IOException.class));
72         importedNames.put("yangModuleInfo", importedName(YangModuleInfo.class));
73
74         return yangModuleInfoTemplate.render(module, ctx, importedNames).body();
75     }
76
77     /**
78      * builds template
79      * @return generated final template
80      */
81     public String generateTemplate() {
82         final StringBuilder sb = new StringBuilder();
83         /* body must be filled before imports method call */
84         final String templateBody = body();
85         sb.append("package ")
86             .append(packageName)
87             .append(";\n")
88             .append(imports())
89             .append(templateBody);
90         return sb.toString();
91     }
92
93     public String generateModelProvider() {
94         return modelProviderTemplate.render(packageName, YangModelBindingProvider.class.getName(), YangModuleInfo.class
95         .getName()).body();
96     }
97
98     /**
99      * walks through map of imports
100      * @return string of imports for template
101      */
102     private String imports() {
103         final StringBuilder sb = new StringBuilder();
104         for (Map.Entry<String, String> entry : importMap.entrySet()) {
105             if (!getRootPackageName(module).equals(entry.getValue())) {
106                 sb.append("import ")
107                     .append(entry.getValue())
108                     .append('.')
109                     .append(entry.getKey())
110                     .append(";\n");
111             }
112         }
113         return sb.toString();
114     }
115
116     private String importedName(final Class<?> cls) {
117         final Type inType = Types.typeForClass(cls);
118         putTypeIntoImports(inType);
119         return getExplicitType(inType);
120     }
121
122     private void putTypeIntoImports(final Type type) {
123         final String typeName = type.getName();
124         final String typePackageName = type.getPackageName();
125         if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
126             return;
127         }
128         if (!importMap.containsKey(typeName)) {
129             importMap.put(typeName, typePackageName);
130         }
131         if (type instanceof ParameterizedType) {
132             final Type[] params = ((ParameterizedType) type).getActualTypeArguments();
133             if (params != null) {
134                 for (Type param : params) {
135                     putTypeIntoImports(param);
136                 }
137             }
138         }
139     }
140
141     private String getExplicitType(final Type type) {
142         final String typePackageName = type.getPackageName();
143         final String typeName = type.getName();
144         final String importedPackageName = importMap.get(typeName);
145         final StringBuilder sb;
146         if (typePackageName.equals(importedPackageName)) {
147             sb = new StringBuilder(type.getName());
148             if (sb.toString().equals("Void")) {
149                 return "void";
150             }
151             addActualTypeParameters(sb, type);
152         } else {
153             if (type.equals(Types.voidType())) {
154                 return "void";
155             }
156             sb = new StringBuilder();
157             if (!typePackageName.isEmpty()) {
158                 sb.append(typePackageName)
159                     .append('.')
160                     .append(type.getName());
161             } else {
162                 sb.append(type.getName());
163             }
164             addActualTypeParameters(sb, type);
165         }
166         return sb.toString();
167     }
168
169     private StringBuilder addActualTypeParameters(final StringBuilder sb, final Type type) {
170         if (type instanceof ParameterizedType) {
171             final Type[] pTypes = ((ParameterizedType) type).getActualTypeArguments();
172             sb.append('<');
173             sb.append(getParameters(pTypes));
174             sb.append('>');
175         }
176         return sb;
177     }
178
179     private String getParameters(final Type[] pTypes) {
180         if (pTypes == null || pTypes.length == 0) {
181             return "?";
182         }
183         final StringBuilder sb = new StringBuilder();
184         int i = 0;
185         for (Type pType : pTypes) {
186             final Type type = pTypes[i];
187             String separator = ",";
188             if (i == (pTypes.length - 1)) {
189                 separator = "";
190             }
191             String wildcardParam = "";
192             if (type.equals(Types.voidType())) {
193                 sb.append("java.lang.Void" + separator);
194             } else {
195                 if (type instanceof WildcardType) {
196                     wildcardParam = "? extends ";
197                 }
198                 sb.append(wildcardParam + getExplicitType(type) + separator);
199                 i = i + 1;
200             }
201         }
202         return sb.toString();
203     }
204
205     public static Module getSortedQName(final Set<Module> modules, final String name) {
206         final TreeMap<Date, Module> sorted = new TreeMap<>();
207         for (Module module : modules) {
208             if (name.equals(module.getName())) {
209                 sorted.put(module.getRevision(), module);
210             }
211         }
212         return sorted.lastEntry().getValue();
213     }
214 }