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