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;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableMap;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.LinkedList;
18 import java.util.List;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.binding.javav2.generator.util.Types;
22 import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil;
23 import org.opendaylight.mdsal.binding.javav2.model.api.Constant;
24 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
25 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
26 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
27 import org.opendaylight.mdsal.binding.javav2.model.api.MethodSignature;
28 import org.opendaylight.mdsal.binding.javav2.model.api.ParameterizedType;
29 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
30 import org.opendaylight.mdsal.binding.javav2.model.api.WildcardType;
31 import org.opendaylight.yangtools.yang.common.QName;
33 public abstract class BaseRenderer {
34 private static final String COMMA = ",";
35 private static final String DOT = ".";
37 private final GeneratedType type;
38 private final Map<String, String> importMap;
40 protected BaseRenderer(final GeneratedType type) {
41 this.type = Preconditions.checkNotNull(type);
42 this.importMap = new HashMap<>();
46 * Implementation needs to call Scala template render() method to generate string body
47 * @return rendered body
49 protected abstract String body();
51 protected GeneratedType getType() {
55 protected String getFromImportMap(@NonNull String typeName) {
56 return importMap.get(typeName);
59 protected void putToImportMap(@NonNull String typeName, String typePackageName) {
60 importMap.put(typeName, typePackageName);
63 protected void putAllToImportMap(@NonNull Map<String, String> imports) {
64 importMap.putAll(imports);
67 protected Map<String, String> getImportMap() {
68 return ImmutableMap.copyOf(importMap);
72 * @param intype type to format and add to imports
73 * @return formatted type
75 protected String importedName(final Type intype) {
76 putTypeIntoImports(type, intype);
77 return getExplicitType(type, intype);
80 protected String importedName(final Class<?> cls) {
81 return importedName(Types.typeForClass(cls));
85 * @return package definition for template
87 protected String packageDefinition() {
88 final StringBuilder sb = new StringBuilder();
90 .append(type.getPackageName())
96 * walks through map of imports
97 * @return string of imports for template
99 private String imports() {
100 final StringBuilder sb = new StringBuilder();
101 if (!importMap.isEmpty()) {
102 for (Map.Entry<String, String> entry : importMap.entrySet()) {
103 if (!hasSamePackage(entry.getValue())) {
105 .append(entry.getValue())
107 .append(entry.getKey())
112 return sb.toString();
116 * Template method which generates method parameters with their types from <code>parameters</code>.
119 * group of generated property instances which are transformed to the method parameters
120 * @return string with the list of the method parameters with their types in JAVA format
122 protected String asArgumentsDeclaration(final Collection<GeneratedProperty> parameters) {
123 final List<CharSequence> strings = new LinkedList<>();
124 if (parameters.iterator().hasNext()) {
125 for (GeneratedProperty parameter : parameters) {
126 final StringBuilder sb = new StringBuilder();
127 sb.append(importedName(parameter.getReturnType()));
129 sb.append(TextTemplateUtil.fieldName(parameter));
133 return String.join(", ", strings);
137 * Checks if package of generated type and imported type is the same
138 * @param importedTypePackageName imported types package name
139 * @return equals packages
141 protected boolean hasSamePackage(final String importedTypePackageName) {
142 return type.getPackageName().equals(importedTypePackageName);
146 * Evaluates if it is necessary to add the package name for type to the map of imports for parentGenType
147 * If it is so the package name is saved to the map imports.
149 * @param parentGenType generated type for which is the map of necessary imports build
150 * @param type JAVA type for which is the necessary of the package import evaluated
152 private void putTypeIntoImports(final GeneratedType parentGenType, final Type type) {
153 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be NULL!");
154 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
155 checkArgument(parentGenType.getPackageName() != null,
156 "Parent Generated Type cannot have Package Name referenced as NULL!");
158 final String typeName = Preconditions.checkNotNull(type.getName());
159 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
160 final String parentTypeName = Preconditions.checkNotNull(parentGenType.getName());
161 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
164 if (!importMap.containsKey(typeName)) {
165 importMap.put(typeName, typePackageName);
167 if (type instanceof ParameterizedType) {
168 final ParameterizedType paramType = (ParameterizedType) type;
169 final Type[] params = paramType.getActualTypeArguments();
170 if (params != null) {
171 for (Type param : params) {
172 putTypeIntoImports(parentGenType, param);
179 * Builds the string which contains either the full path to the type (package name with type) or only type name
180 * if the package is among imports.
182 * @param parentGenType generated type which contains type
183 * @param type JAVA type for which is the string with type info generated
184 * @return string with type name for type in the full format or in the short format
186 private String getExplicitType(final GeneratedType parentGenType, final Type type) {
187 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
188 checkArgument(importMap != null, "Imports Map cannot be NULL!");
190 final String typePackageName = Preconditions.checkNotNull(type.getPackageName());
191 final String typeName = Preconditions.checkNotNull(type.getName());
192 final String importedPackageName = importMap.get(typeName);
193 final StringBuilder sb;
194 if (typePackageName.equals(importedPackageName)) {
195 sb = new StringBuilder(typeName);
196 addActualTypeParameters(sb, type, parentGenType);
197 if (sb.toString().equals("Void")) {
201 sb = new StringBuilder();
202 if (!typePackageName.isEmpty()) {
203 sb.append(typePackageName).append(DOT).append(typeName);
205 sb.append(type.getName());
207 if (type.equals(Types.voidType())) {
210 addActualTypeParameters(sb, type, parentGenType);
212 return sb.toString();
216 * Adds actual type parameters from type to builder if type is ParametrizedType.
218 * @param sb string builder which contains type name
219 * @param type JAVA Type for which is the string with type info generated
220 * @param parentGenType generated type which contains type
221 * @return adds actual type parameters to builder
223 private StringBuilder addActualTypeParameters(final StringBuilder sb, final Type type, final GeneratedType parentGenType) {
224 if (type instanceof ParameterizedType) {
225 final ParameterizedType pType = (ParameterizedType) type;
226 final Type[] pTypes = pType.getActualTypeArguments();
228 sb.append(getParameters(parentGenType, pTypes));
234 protected GeneratedProperty findProperty(final GeneratedTransferObject gto, String name) {
235 for (GeneratedProperty prop : gto.getProperties()) {
236 if (name.equals(prop.getName())) {
240 final GeneratedTransferObject parent = gto.getSuperType();
241 if (parent != null) {
242 return findProperty(parent, name);
249 * @return string with constant wrapped in code
251 protected String emitConstant(final Constant constant) {
252 final StringBuilder sb = new StringBuilder();
253 final Object qname = constant.getValue();
254 sb.append("public static final ")
255 .append(importedName(constant.getType()))
257 .append(constant.getName())
259 if (qname instanceof QName) {
260 sb.append(QName.class.getName())
261 .append(".create(\"")
262 .append(((QName) qname).getNamespace().toString())
264 .append(((QName) qname).getFormattedRevision())
266 .append(((QName) qname).getLocalName())
267 .append("\").intern()");
272 return sb.toString();
276 * Generates the string with all actual type parameters from
278 * @param parentGenType generated type for which is the JAVA code generated
279 * @param pTypes array of Type instances = actual type parameters
280 * @return string with all actual type parameters from pTypes
282 private String getParameters(final GeneratedType parentGenType, final Type[] pTypes) {
283 if (pTypes == null || pTypes.length == 0) {
286 final StringBuilder sb = new StringBuilder();
287 for (int i = 0; i < pTypes.length; i++) {
288 final Type t = pTypes[i];
290 String separator = COMMA;
291 if (i == (pTypes.length - 1)) {
296 if (t.equals(Types.voidType())) {
297 sb.append("java.lang.Void")
302 String wildcardParam = "";
303 if (t instanceof WildcardType) {
304 wildcardParam = "? extends ";
307 sb.append(wildcardParam).append(getExplicitType(parentGenType, t)).append(separator);
310 return sb.toString();
314 * Template method which generates method parameters with their types from <code>parameters</code>.
315 * InterfaceTemplate / UnionTemaplate
317 * @param parameters list of parameter instances which are transformed to the method parameters
318 * @return string with the list of the method parameters with their types in JAVA format
320 protected String generateParameters(final List<MethodSignature.Parameter> parameters) {
321 final List<CharSequence> strings = new LinkedList<>();
322 if (!parameters.isEmpty()) {
323 for (MethodSignature.Parameter parameter : parameters) {
324 final StringBuilder sb = new StringBuilder();
325 sb.append(importedName(parameter.getType()));
327 sb.append(parameter.getName());
331 return String.join(", ", strings);
335 * Template method which generates the getter method for field
337 * @param field generated property with data about field which is generated as the getter method
338 * @return string with the getter method source code in JAVA format
340 protected String getterMethod(final GeneratedProperty field) {
341 final StringBuilder sb = new StringBuilder();
342 final String name = TextTemplateUtil.fieldName(field);
343 final String importedName = Preconditions.checkNotNull(importedName(field.getReturnType()));
345 .append(importedName)
347 .append(TextTemplateUtil.getterMethodName(field))
351 if (!(field.getReturnType() instanceof ParameterizedType)
352 && importedName.contains("[]")) {
353 sb.append(" == null ? null : ")
358 return sb.toString();
363 * @return generated final template
365 public String generateTemplate() {
366 final StringBuilder sb = new StringBuilder();
367 /* sb body must be filled before imports method call */
368 final String templateBody = body();
369 sb.append(packageDefinition())
371 .append(templateBody);
372 return sb.toString();