2 * Copyright (c) 2013 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
8 package org.opendaylight.mdsal.binding.java.api.generator;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static org.opendaylight.mdsal.binding.java.api.generator.Constants.COMMA;
13 import java.util.ArrayList;
14 import java.util.LinkedHashMap;
15 import java.util.List;
17 import org.opendaylight.mdsal.binding.model.api.AnnotationType;
18 import org.opendaylight.mdsal.binding.model.api.Constant;
19 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
20 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
21 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
22 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
23 import org.opendaylight.mdsal.binding.model.api.MethodSignature;
24 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
25 import org.opendaylight.mdsal.binding.model.api.Type;
26 import org.opendaylight.mdsal.binding.model.api.WildcardType;
27 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
28 import org.opendaylight.mdsal.binding.model.util.Types;
30 public final class GeneratorUtil {
31 private GeneratorUtil() {
32 throw new UnsupportedOperationException();
36 * Returns the map of imports. The map maps the type name to the package name. To the map are added packages
37 * for <code>genType</code> and for all enclosed types, constants, methods (parameter types, return values),
40 * @param genType generated type for which the map of the imports is created
41 * @return map of the necessary imports
42 * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
44 static Map<String, JavaTypeName> createImports(final GeneratedType genType) {
45 if (genType == null) {
46 throw new IllegalArgumentException("Generated Type cannot be NULL!");
48 final Map<String, JavaTypeName> imports = new LinkedHashMap<>();
50 List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
51 if (!childGeneratedTypes.isEmpty()) {
52 for (GeneratedType genTypeChild : childGeneratedTypes) {
53 imports.putAll(createImports(genTypeChild));
58 if (genType instanceof GeneratedTransferObject
59 && isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) {
60 putTypeIntoImports(genType, Types.typeForClass(java.util.regex.Pattern.class), imports);
63 final List<MethodSignature> methods = genType.getMethodDefinitions();
65 if (methods != null) {
66 for (final MethodSignature method : methods) {
67 final Type methodReturnType = method.getReturnType();
68 putTypeIntoImports(genType, methodReturnType, imports);
69 for (final MethodSignature.Parameter methodParam : method.getParameters()) {
70 putTypeIntoImports(genType, methodParam.getType(), imports);
72 for (final AnnotationType at : method.getAnnotations()) {
73 putTypeIntoImports(genType, at, imports);
79 if (genType instanceof GeneratedTransferObject) {
80 final GeneratedTransferObject genTO = (GeneratedTransferObject) genType;
81 final List<GeneratedProperty> properties = genTO.getProperties();
82 if (properties != null) {
83 for (GeneratedProperty property : properties) {
84 final Type propertyType = property.getReturnType();
85 putTypeIntoImports(genType, propertyType, imports);
93 * Evaluates if it is necessary to add the package name for <code>type</code> to the map of imports for
94 * <code>parentGenType</code>. If it is so the package name is saved to the map <code>imports</code>.
96 * @param parentGenType generated type for which is the map of the necessary imports built
97 * @param type JAVA <code>Type</code> for which is the necessary of the package import evaluated
98 * @param imports map of the imports for <code>parentGenType</code>
99 * @throws IllegalArgumentException
101 * <li>if the <code>parentGenType</code> equals
102 * <code>null</code></li>
103 * <li>if the name of <code>parentGenType</code> equals
104 * <code>null</code></li>
105 * <li>if the name of the package of <code>parentGenType</code>
106 * equals <code>null</code></li>
107 * <li>if the <code>type</code> equals <code>null</code></li>
108 * <li>if the name of <code>type</code> equals <code>null</code>
110 * <li>if the name of the package of <code>type</code> equals
111 * <code>null</code></li>
114 static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
115 final Map<String, JavaTypeName> imports) {
116 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be "
118 checkArgument(parentGenType.getName() != null, "Parent Generated Type name cannot be NULL!");
119 checkArgument(parentGenType.getPackageName() != null,
120 "Parent Generated Type cannot have Package Name referenced as NULL!");
121 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
123 checkArgument(type.getName() != null, "Type name cannot be NULL!");
124 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
126 final String typeName = type.getName();
127 final String typePackageName = type.getPackageName();
128 final String parentTypeName = parentGenType.getName();
129 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
132 if (!imports.containsKey(typeName)) {
133 imports.put(typeName, type.getIdentifier());
135 if (type instanceof ParameterizedType) {
136 final ParameterizedType paramType = (ParameterizedType) type;
137 final Type[] params = paramType.getActualTypeArguments();
138 if (params != null) {
139 for (Type param : params) {
140 putTypeIntoImports(parentGenType, param, imports);
147 * Checks if the constant with the name <code>constName</code> is in the list of the constant definition for
148 * <code>genTO</code>.
150 * @param constName string with the name of constant which is sought
151 * @param genTO generated transfer object in which is <code>constName</code> sought
152 * @return boolean value
154 * <li>true - if <code>constName</code> is in the list of the
155 * constant definition for <code>genTO</code></li>
156 * <li>false - in other cases</li>
158 * @throws IllegalArgumentException
160 * <li>if <code>constName</code> equals <code>null</code></li>
161 * <li>if <code>genTO</code> equals <code>null</code></li>
164 static boolean isConstantInTO(final String constName, final GeneratedTransferObject genTO) {
165 if (constName == null || genTO == null) {
166 throw new IllegalArgumentException();
168 List<Constant> consts = genTO.getConstantDefinitions();
169 for (Constant cons : consts) {
170 if (cons.getName().equals(constName)) {
178 * Creates the map which maps the type name to package name and contains only package names for enclosed types
179 * of <code>genType</code> and recursively their enclosed types.
181 * @param genType JAVA <code>Type</code> for which is the map created
182 * @return map of the package names for all the enclosed types and recursively their enclosed types
184 static Map<String, String> createChildImports(final GeneratedType genType) {
185 Map<String, String> childImports = new LinkedHashMap<>();
186 for (GeneratedType genTypeChild : genType.getEnclosedTypes()) {
187 createChildImports(genTypeChild);
188 childImports.put(genTypeChild.getName(), genTypeChild.getPackageName());
194 * Builds the string which contains either the full path to the type (package name with type) or only type name
195 * if the package is among <code>imports</code>.
197 * @param parentGenType generated type which contains <code>type</code>
198 * @param type JAVA <code>Type</code> for which is the string with type info generated
199 * @param imports map of necessary imports for <code>parentGenType</code>
200 * @return string with type name for <code>type</code> in the full format or in the short format
201 * @throws IllegalArgumentException
203 * <li>if the <code>type</code> equals <code>null</code></li>
204 * <li>if the name of the <code>type</code> equals
205 * <code>null</code></li>
206 * <li>if the name of the package of the <code>type</code>
207 * equals <code>null</code></li>
208 * <li>if the <code>imports</code> equals <code>null</code></li>
211 static String getExplicitType(final GeneratedType parentGenType, final Type type,
212 final Map<String, JavaTypeName> imports) {
213 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
214 checkArgument(imports != null, "Imports Map cannot be NULL!");
216 final JavaTypeName importedType = imports.get(type.getName());
217 final StringBuilder builder = new StringBuilder();
218 if (type.getIdentifier().equals(importedType)) {
219 builder.append(type.getName());
220 addActualTypeParameters(builder, type, parentGenType, imports);
221 if (builder.toString().equals("Void")) {
225 if (type.equals(Types.voidType())) {
228 builder.append(type.getFullyQualifiedName());
229 addActualTypeParameters(builder, type, parentGenType, imports);
231 return builder.toString();
235 * Adds actual type parameters from <code>type</code> to <code>builder</code> if <code>type</code> is
236 * <code>ParametrizedType</code>.
238 * @param builder string builder which contains type name
239 * @param type JAVA <code>Type</code> for which is the string with type info generated
240 * @param parentGenType generated type which contains <code>type</code>
241 * @param imports map of necessary imports for <code>parentGenType</code>
242 * @return if <code>type</code> is of the type <code>ParametrizedType</code> <br />
243 * <li>then <code>builder</code> + actual <code>type</code>
244 * parameters</li> <li>else only <code>builder</code></li>
246 private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type,
247 final GeneratedType parentGenType, final Map<String, JavaTypeName> imports) {
248 if (type instanceof ParameterizedType) {
249 final ParameterizedType pType = (ParameterizedType) type;
250 final Type[] pTypes = pType.getActualTypeArguments();
251 builder.append('<').append(getParameters(parentGenType, pTypes, imports)).append('>');
257 * Generates the string with all actual type parameters from <code>pTypes</code>.
259 * @param parentGenType generated type for which is the JAVA code generated
260 * @param paramTypes array of <code>Type</code> instances = actual type parameters
261 * @param availableImports map of imports for <code>parentGenType</code>
262 * @return string with all actual type parameters from <code>pTypes</code>
264 private static String getParameters(final GeneratedType parentGenType, final Type[] paramTypes,
265 final Map<String, JavaTypeName> availableImports) {
267 if (paramTypes == null || paramTypes.length == 0) {
270 final StringBuilder builder = new StringBuilder();
271 for (int i = 0; i < paramTypes.length; i++) {
272 final Type t = paramTypes[i];
274 String separator = COMMA;
275 if (i == paramTypes.length - 1) {
279 if (Types.voidType().equals(t)) {
280 builder.append("java.lang.Void").append(separator);
282 if (t instanceof WildcardType) {
283 builder.append("? extends ");
285 builder.append(getExplicitType(parentGenType, t, availableImports)).append(separator);
288 return builder.toString();
292 * Returns the reference to highest (top parent) Generated Transfer Object.
294 * @param childTransportObject is generated transfer object which can be extended by other generated transfer object
295 * @return in first case that <code>childTransportObject</code> is not extended then
296 * <code>childTransportObject</code> is returned. In second case the method is recursive called until first
298 * @throws IllegalArgumentException if <code>childTransportObject</code> equals <code>null</code>
300 static GeneratedTransferObject getTopParentTransportObject(final GeneratedTransferObject childTransportObject) {
301 if (childTransportObject == null) {
302 throw new IllegalArgumentException("Parameter childTransportObject can't be null.");
304 if (childTransportObject.getSuperType() == null) {
305 return childTransportObject;
308 return getTopParentTransportObject(childTransportObject.getSuperType());
312 * Selects from input list of properties only those which have read only attribute set to true.
314 * @param properties list of properties of generated transfer object
315 * @return subset of <code>properties</code> which have read only attribute set to true
317 static List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(final List<GeneratedProperty> properties) {
318 List<GeneratedProperty> readOnlyProperties = new ArrayList<>();
319 if (properties != null) {
320 for (final GeneratedProperty property : properties) {
321 if (property.isReadOnly()) {
322 readOnlyProperties.add(property);
326 return readOnlyProperties;
330 * Returns the list of the read only properties of all extending generated transfer object from <code>genTO</code>
331 * to highest parent generated transfer object.
333 * @param genTO generated transfer object for which is the list of read only properties generated
334 * @return list of all read only properties from actual to highest parent generated transfer object. In case when
335 * extension exists the method is recursive called.
337 static List<GeneratedProperty> getPropertiesOfAllParents(final GeneratedTransferObject genTO) {
338 List<GeneratedProperty> propertiesOfAllParents = new ArrayList<>();
339 if (genTO.getSuperType() != null) {
340 final List<GeneratedProperty> allPropertiesOfTO = genTO.getSuperType().getProperties();
341 List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
342 propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
343 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType()));
345 return propertiesOfAllParents;