2 * Copyright (c) 2017 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
9 package org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers;
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static org.opendaylight.mdsal.binding.javav2.util.BindingMapping.PATTERN_CONSTANT_NAME;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.ImmutableMap;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.LinkedList;
21 import java.util.List;
23 import java.util.Optional;
24 import org.apache.commons.text.StringEscapeUtils;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
27 import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil;
28 import org.opendaylight.mdsal.binding.javav2.model.api.Constant;
29 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
30 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
31 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
32 import org.opendaylight.mdsal.binding.javav2.model.api.MethodSignature;
33 import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
34 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
35 import org.opendaylight.mdsal.binding.javav2.model.api.WildcardType;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.common.Revision;
39 public abstract class BaseRenderer {
40 private static final String COMMA = ",";
41 private static final String DOT = ".";
43 private final GeneratedType type;
44 private final Map<String, String> importMap;
46 * list of all imported names for template
48 private final Map<String, String> importedNames = new HashMap<>();
50 protected BaseRenderer(final GeneratedType type) {
51 this.type = Preconditions.checkNotNull(type);
52 this.importMap = new HashMap<>();
56 * Implementation needs to call Scala template render() method to generate string body
57 * @return rendered body
59 protected abstract String body();
61 protected GeneratedType getType() {
65 protected Map<String, String> getImportedNames() {
69 protected String getFromImportMap(@NonNull final String typeName) {
70 return importMap.get(typeName);
73 protected void putToImportMap(@NonNull final String typeName, final String typePackageName) {
74 importMap.put(typeName, typePackageName);
77 protected void putAllToImportMap(@NonNull final Map<String, String> imports) {
78 importMap.putAll(imports);
81 protected Map<String, String> getImportMap() {
82 return ImmutableMap.copyOf(importMap);
86 * @param intype type to format and add to imports
87 * @return formatted type
89 protected String importedName(final Type intype) {
90 putTypeIntoImports(type, intype);
91 return getExplicitType(type, intype);
94 protected String importedName(final Class<?> cls) {
95 return importedName(Types.typeForClass(cls));
99 * @return package definition for template
101 protected String packageDefinition() {
102 final StringBuilder sb = new StringBuilder();
103 sb.append("package ")
104 .append(type.getPackageName())
106 return sb.toString();
110 * walks through map of imports
111 * @return string of imports for template
113 private String imports() {
114 final StringBuilder sb = new StringBuilder();
115 if (!importMap.isEmpty()) {
116 for (Map.Entry<String, String> entry : importMap.entrySet()) {
117 if (!hasSamePackage(entry.getValue())) {
119 .append(entry.getValue())
121 .append(entry.getKey())
126 return sb.toString();
130 * Template method which generates method parameters with their types from <code>parameters</code>.
133 * group of generated property instances which are transformed to the method parameters
134 * @return string with the list of the method parameters with their types in JAVA format
136 protected String asArgumentsDeclaration(final Collection<GeneratedProperty> parameters) {
137 final List<CharSequence> strings = new LinkedList<>();
138 if (parameters.iterator().hasNext()) {
139 for (GeneratedProperty parameter : parameters) {
140 final StringBuilder sb = new StringBuilder();
141 sb.append(importedName(parameter.getReturnType()));
143 sb.append(TextTemplateUtil.fieldName(parameter));
147 return String.join(", ", strings);
151 * Checks if package of generated type and imported type is the same
152 * @param importedTypePackageName imported types package name
153 * @return equals packages
155 protected boolean hasSamePackage(final String importedTypePackageName) {
156 return type.getPackageName().equals(importedTypePackageName);
160 * Evaluates if it is necessary to add the package name for type to the map of imports for parentGenType
161 * If it is so the package name is saved to the map imports.
163 * @param parentGenType generated type for which is the map of necessary imports build
164 * @param type JAVA type for which is the necessary of the package import evaluated
166 private void putTypeIntoImports(final GeneratedType parentGenType, final Type type) {
167 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be NULL!");
168 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
169 checkArgument(parentGenType.getPackageName() != null,
170 "Parent Generated Type cannot have Package Name referenced as NULL!");
172 final String typeName = Preconditions.checkNotNull(type.getName());
173 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
174 final String parentTypeName = Preconditions.checkNotNull(parentGenType.getName());
175 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
178 if (!importMap.containsKey(typeName)) {
179 importMap.put(typeName, typePackageName);
181 if (type instanceof ParameterizedType) {
182 final ParameterizedType paramType = (ParameterizedType) type;
183 final Type[] params = paramType.getActualTypeArguments();
184 if (params != null) {
185 for (Type param : params) {
186 putTypeIntoImports(parentGenType, param);
193 * Builds the string which contains either the full path to the type (package name with type) or only type name
194 * if the package is among imports.
196 * @param parentGenType generated type which contains type
197 * @param type JAVA type for which is the string with type info generated
198 * @return string with type name for type in the full format or in the short format
200 private String getExplicitType(final GeneratedType parentGenType, final Type type) {
201 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
202 checkArgument(importMap != null, "Imports Map cannot be NULL!");
204 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
205 final String typeName = Preconditions.checkNotNull(type.getName());
206 final String importedPackageName = importMap.get(typeName);
207 final StringBuilder sb;
208 if (typePackageName.equals(importedPackageName)) {
209 sb = new StringBuilder(typeName);
210 addActualTypeParameters(sb, type, parentGenType);
211 if (sb.toString().equals("Void")) {
215 sb = new StringBuilder();
216 if (!typePackageName.isEmpty()) {
217 sb.append(typePackageName).append(DOT).append(typeName);
219 sb.append(type.getName());
221 if (type.equals(Types.voidType())) {
224 addActualTypeParameters(sb, type, parentGenType);
226 return sb.toString();
230 * Adds actual type parameters from type to builder if type is ParametrizedType.
232 * @param sb string builder which contains type name
233 * @param type JAVA Type for which is the string with type info generated
234 * @param parentGenType generated type which contains type
235 * @return adds actual type parameters to builder
237 private StringBuilder addActualTypeParameters(final StringBuilder sb, final Type type, final GeneratedType parentGenType) {
238 if (type instanceof ParameterizedType) {
239 final ParameterizedType pType = (ParameterizedType) type;
240 final Type[] pTypes = pType.getActualTypeArguments();
242 sb.append(getParameters(parentGenType, pTypes));
248 protected GeneratedProperty findProperty(final GeneratedTransferObject gto, final String name) {
249 for (GeneratedProperty prop : gto.getProperties()) {
250 if (name.equals(prop.getName())) {
254 final GeneratedTransferObject parent = gto.getSuperType();
255 if (parent != null) {
256 return findProperty(parent, name);
262 * Generates the string with all actual type parameters from
264 * @param parentGenType generated type for which is the JAVA code generated
265 * @param pTypes array of Type instances = actual type parameters
266 * @return string with all actual type parameters from pTypes
268 private String getParameters(final GeneratedType parentGenType, final Type[] pTypes) {
269 if (pTypes == null || pTypes.length == 0) {
272 final StringBuilder sb = new StringBuilder();
273 for (int i = 0; i < pTypes.length; i++) {
274 final Type t = pTypes[i];
276 String separator = COMMA;
277 if (i == pTypes.length - 1) {
282 if (t.equals(Types.voidType())) {
283 sb.append("java.lang.Void")
288 String wildcardParam = "";
289 if (t instanceof WildcardType) {
290 wildcardParam = "? extends ";
293 sb.append(wildcardParam).append(getExplicitType(parentGenType, t)).append(separator);
296 return sb.toString();
300 * Template method which generates method parameters with their types from <code>parameters</code>.
301 * InterfaceTemplate / UnionTemaplate
303 * @param parameters list of parameter instances which are transformed to the method parameters
304 * @return string with the list of the method parameters with their types in JAVA format
306 protected String generateParameters(final List<MethodSignature.Parameter> parameters) {
307 final List<CharSequence> strings = new LinkedList<>();
308 if (!parameters.isEmpty()) {
309 for (MethodSignature.Parameter parameter : parameters) {
310 final StringBuilder sb = new StringBuilder();
311 sb.append(importedName(parameter.getType()));
313 sb.append(parameter.getName());
317 return String.join(", ", strings);
321 * Template method which generates the getter method for field
323 * @param field generated property with data about field which is generated as the getter method
324 * @return string with the getter method source code in JAVA format
326 protected String getterMethod(final GeneratedProperty field) {
327 final StringBuilder sb = new StringBuilder();
328 final String name = TextTemplateUtil.fieldName(field);
329 final String importedName = Preconditions.checkNotNull(importedName(field.getReturnType()));
331 .append(importedName)
333 .append(TextTemplateUtil.getterMethodName(field))
337 if (!(field.getReturnType() instanceof ParameterizedType)
338 && importedName.contains("[]")) {
339 sb.append(" == null ? null : ")
344 return sb.toString();
349 * @return generated final template
351 public String generateTemplate() {
352 final StringBuilder sb = new StringBuilder();
353 /* sb body must be filled before imports method call */
354 final String templateBody = body();
355 sb.append(packageDefinition())
357 .append(templateBody);
358 return sb.toString();