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.MethodSignature;
23 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
24 import org.opendaylight.mdsal.binding.model.api.Type;
25 import org.opendaylight.mdsal.binding.model.api.WildcardType;
26 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
27 import org.opendaylight.mdsal.binding.model.util.Types;
29 public final class GeneratorUtil {
32 * It doesn't have the sense to create the instances of this class.
34 private GeneratorUtil() {
35 throw new UnsupportedOperationException();
39 * Returns the map of imports. The map maps the type name to the package
40 * name. To the map are added packages for <code>genType</code> and for all
41 * enclosed types, constants, methods (parameter types, return values),
45 * generated type for which the map of the imports is created
46 * @return map of the necessary imports
47 * @throws IllegalArgumentException
48 * if <code>genType</code> equals <code>null</code>
50 static Map<String, String> createImports(final GeneratedType genType) {
51 if (genType == null) {
52 throw new IllegalArgumentException("Generated Type cannot be NULL!");
54 final Map<String, String> imports = new LinkedHashMap<>();
56 List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
57 if (!childGeneratedTypes.isEmpty()) {
58 for (GeneratedType genTypeChild : childGeneratedTypes) {
59 imports.putAll(createImports(genTypeChild));
64 if (genType instanceof GeneratedTransferObject
65 && isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) {
66 putTypeIntoImports(genType, Types.typeForClass(java.util.regex.Pattern.class), imports);
67 putTypeIntoImports(genType, Types.typeForClass(java.util.Arrays.class), imports);
68 putTypeIntoImports(genType, Types.typeForClass(java.util.ArrayList.class), imports);
71 final List<MethodSignature> methods = genType.getMethodDefinitions();
73 if (methods != null) {
74 for (final MethodSignature method : methods) {
75 final Type methodReturnType = method.getReturnType();
76 putTypeIntoImports(genType, methodReturnType, imports);
77 for (final MethodSignature.Parameter methodParam : method.getParameters()) {
78 putTypeIntoImports(genType, methodParam.getType(), imports);
80 for (final AnnotationType at : method.getAnnotations()) {
81 putTypeIntoImports(genType, at, imports);
87 if (genType instanceof GeneratedTransferObject) {
88 final GeneratedTransferObject genTO = (GeneratedTransferObject) genType;
89 final List<GeneratedProperty> properties = genTO.getProperties();
90 if (properties != null) {
91 for (GeneratedProperty property : properties) {
92 final Type propertyType = property.getReturnType();
93 putTypeIntoImports(genType, propertyType, imports);
101 * Evaluates if it is necessary to add the package name for
102 * <code>type</code> to the map of imports for <code>parentGenType</code>.
103 * If it is so the package name is saved to the map <code>imports</code>.
105 * @param parentGenType
106 * generated type for which is the map of the necessary imports
109 * JAVA <code>Type</code> for which is the necessary of the
110 * package import evaluated
112 * map of the imports for <code>parentGenType</code>
113 * @throws IllegalArgumentException
115 * <li>if the <code>parentGenType</code> equals
116 * <code>null</code></li>
117 * <li>if the name of <code>parentGenType</code> equals
118 * <code>null</code></li>
119 * <li>if the name of the package of <code>parentGenType</code>
120 * equals <code>null</code></li>
121 * <li>if the <code>type</code> equals <code>null</code></li>
122 * <li>if the name of <code>type</code> equals <code>null</code>
124 * <li>if the name of the package of <code>type</code> equals
125 * <code>null</code></li>
128 static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
129 final Map<String, String> imports) {
130 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be "
132 checkArgument(parentGenType.getName() != null, "Parent Generated Type name cannot be NULL!");
133 checkArgument(parentGenType.getPackageName() != null,
134 "Parent Generated Type cannot have Package Name referenced as NULL!");
135 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
137 checkArgument(type.getName() != null, "Type name cannot be NULL!");
138 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
140 final String typeName = type.getName();
141 final String typePackageName = type.getPackageName();
142 final String parentTypeName = parentGenType.getName();
143 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
146 if (!imports.containsKey(typeName)) {
147 imports.put(typeName, typePackageName);
149 if (type instanceof ParameterizedType) {
150 final ParameterizedType paramType = (ParameterizedType) type;
151 final Type[] params = paramType.getActualTypeArguments();
152 if (params != null) {
153 for (Type param : params) {
154 putTypeIntoImports(parentGenType, param, imports);
161 * Checks if the constant with the name <code>constName</code> is in the
162 * list of the constant definition for <code>genTO</code>.
165 * string with the name of constant which is sought
167 * generated transfer object in which is <code>constName</code>
169 * @return boolean value
171 * <li>true - if <code>constName</code> is in the list of the
172 * constant definition for <code>genTO</code></li>
173 * <li>false - in other cases</li>
175 * @throws IllegalArgumentException
177 * <li>if <code>constName</code> equals <code>null</code></li>
178 * <li>if <code>genTO</code> equals <code>null</code></li>
181 static boolean isConstantInTO(final String constName, final GeneratedTransferObject genTO) {
182 if (constName == null || genTO == null) {
183 throw new IllegalArgumentException();
185 List<Constant> consts = genTO.getConstantDefinitions();
186 for (Constant cons : consts) {
187 if (cons.getName().equals(constName)) {
195 * Creates the map which maps the type name to package name and contains
196 * only package names for enclosed types of <code>genType</code> and
197 * recursivelly their enclosed types.
200 * JAVA <code>Type</code> for which is the map created
201 * @return map of the package names for all the enclosed types and
202 * recursivelly their enclosed types
204 static Map<String, String> createChildImports(final GeneratedType genType) {
205 Map<String, String> childImports = new LinkedHashMap<>();
206 List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
207 if (!childGeneratedTypes.isEmpty()) {
208 for (GeneratedType genTypeChild : childGeneratedTypes) {
209 createChildImports(genTypeChild);
210 childImports.put(genTypeChild.getName(), genTypeChild.getPackageName());
217 * Builds the string which contains either the full path to the type
218 * (package name with type) or only type name if the package is among
219 * <code>imports</code>.
221 * @param parentGenType
222 * generated type which contains <code>type</code>
224 * JAVA <code>Type</code> for which is the string with type info
227 * map of necessary imports for <code>parentGenType</code>
228 * @return string with type name for <code>type</code> in the full format or
229 * in the short format
230 * @throws IllegalArgumentException
232 * <li>if the <code>type</code> equals <code>null</code></li>
233 * <li>if the name of the <code>type</code> equals
234 * <code>null</code></li>
235 * <li>if the name of the package of the <code>type</code>
236 * equals <code>null</code></li>
237 * <li>if the <code>imports</code> equals <code>null</code></li>
240 static String getExplicitType(final GeneratedType parentGenType, final Type type,
241 final Map<String, String> imports) {
243 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
244 checkArgument(type.getName() != null, "Type name cannot be NULL!");
245 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
246 checkArgument(imports != null, "Imports Map cannot be NULL!");
248 final String typePackageName = type.getPackageName();
249 final String typeName = type.getName();
250 final String importedPackageName = imports.get(typeName);
251 final StringBuilder builder;
253 if (typePackageName.equals(importedPackageName)) {
254 builder = new StringBuilder(type.getName());
255 addActualTypeParameters(builder, type, parentGenType, imports);
256 if (builder.toString().equals("Void")) {
260 builder = new StringBuilder();
261 if (!typePackageName.isEmpty()) {
262 builder.append(typePackageName).append(Constants.DOT).append(type.getName());
264 builder.append(type.getName());
266 if (type.equals(Types.voidType())) {
269 addActualTypeParameters(builder, type, parentGenType, imports);
271 return builder.toString();
275 * Adds actual type parameters from <code>type</code> to
276 * <code>builder</code> if <code>type</code> is
277 * <code>ParametrizedType</code>.
280 * string builder which contains type name
282 * JAVA <code>Type</code> for which is the string with type info
284 * @param parentGenType
285 * generated type which contains <code>type</code>
287 * map of necessary imports for <code>parentGenType</code>
288 * @return if <code>type</code> is of the type <code>ParametrizedType</code> <br />
289 * <li>then <code>builder</code> + actual <code>type</code>
290 * parameters</li> <li>else only <code>builder</code></li>
292 private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type,
293 final GeneratedType parentGenType, final Map<String, String> imports) {
294 if (type instanceof ParameterizedType) {
295 final ParameterizedType pType = (ParameterizedType) type;
296 final Type[] pTypes = pType.getActualTypeArguments();
298 builder.append(getParameters(parentGenType, pTypes, imports));
305 * Generates the string with all actual type parameters from
306 * <code>pTypes</code>
308 * @param parentGenType
309 * generated type for which is the JAVA code generated
311 * array of <code>Type</code> instances = actual type parameters
312 * @param availableImports
313 * map of imports for <code>parentGenType</code>
314 * @return string with all actual type parameters from <code>pTypes</code>
316 private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
317 final Map<String, String> availableImports) {
319 if (pTypes == null || pTypes.length == 0) {
322 final StringBuilder builder = new StringBuilder();
323 for (int i = 0; i < pTypes.length; i++) {
324 final Type t = pTypes[i];
326 String separator = COMMA;
327 if (i == (pTypes.length - 1)) {
331 if (Types.voidType().equals(t)) {
332 builder.append("java.lang.Void").append(separator);
334 if (t instanceof WildcardType) {
335 builder.append("? extends ");
337 builder.append(getExplicitType(parentGenType, t, availableImports)).append(separator);
340 return builder.toString();
344 * Returns the reference to highest (top parent) Generated Transfer Object.
346 * @param childTransportObject
347 * is generated transfer object which can be extended by other
348 * generated transfer object
349 * @return in first case that <code>childTransportObject</code> isn't
350 * extended then <code>childTransportObject</code> is returned. In
351 * second case the method is recursive called until first case.
352 * @throws IllegalArgumentException
353 * if <code>childTransportObject</code> equals <code>null</code>
355 static GeneratedTransferObject getTopParentTransportObject(final GeneratedTransferObject childTransportObject) {
356 if (childTransportObject == null) {
357 throw new IllegalArgumentException("Parameter childTransportObject can't be null.");
359 if (childTransportObject.getSuperType() == null) {
360 return childTransportObject;
362 return getTopParentTransportObject(childTransportObject.getSuperType());
367 * Selects from input list of properties only those which have read only
368 * attribute set to true.
371 * list of properties of generated transfer object
372 * @return subset of <code>properties</code> which have read only attribute
375 static List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(final List<GeneratedProperty> properties) {
376 List<GeneratedProperty> readOnlyProperties = new ArrayList<>();
377 if (properties != null) {
378 for (final GeneratedProperty property : properties) {
379 if (property.isReadOnly()) {
380 readOnlyProperties.add(property);
384 return readOnlyProperties;
388 * Returns the list of the read only properties of all extending generated
389 * transfer object from <code>genTO</code> to highest parent generated
393 * generated transfer object for which is the list of read only
394 * properties generated
395 * @return list of all read only properties from actual to highest parent
396 * generated transfer object. In case when extension exists the
397 * method is recursive called.
399 static List<GeneratedProperty> getPropertiesOfAllParents(final GeneratedTransferObject genTO) {
400 List<GeneratedProperty> propertiesOfAllParents = new ArrayList<>();
401 if (genTO.getSuperType() != null) {
402 final List<GeneratedProperty> allPropertiesOfTO = genTO.getSuperType().getProperties();
403 List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
404 propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
405 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType()));
407 return propertiesOfAllParents;