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.yangtools.sal.java.api.generator;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static org.opendaylight.yangtools.sal.java.api.generator.Constants.COMMA;
13 import java.util.ArrayList;
14 import java.util.LinkedHashMap;
15 import java.util.List;
18 import org.opendaylight.yangtools.binding.generator.util.TypeConstants;
19 import org.opendaylight.yangtools.binding.generator.util.Types;
20 import org.opendaylight.yangtools.sal.binding.model.api.AnnotationType;
21 import org.opendaylight.yangtools.sal.binding.model.api.Constant;
22 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty;
23 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject;
24 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType;
25 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature;
26 import org.opendaylight.yangtools.sal.binding.model.api.ParameterizedType;
27 import org.opendaylight.yangtools.sal.binding.model.api.Type;
28 import org.opendaylight.yangtools.sal.binding.model.api.WildcardType;
30 public final class GeneratorUtil {
33 * It doesn't have the sense to create the instances of this class.
35 private GeneratorUtil() {
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 public static Map<String, String> createImports(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);
102 * Evaluates if it is necessary to add the package name for
103 * <code>type</code> to the map of imports for <code>parentGenType</code>.
104 * If it is so the package name is saved to the map <code>imports</code>.
106 * @param parentGenType
107 * generated type for which is the map of the necessary imports
110 * JAVA <code>Type</code> for which is the necessary of the
111 * package import evaluated
113 * map of the imports for <code>parentGenType</code>
114 * @throws IllegalArgumentException
116 * <li>if the <code>parentGenType</code> equals
117 * <code>null</code></li>
118 * <li>if the name of <code>parentGenType</code> equals
119 * <code>null</code></li>
120 * <li>if the name of the package of <code>parentGenType</code>
121 * equals <code>null</code></li>
122 * <li>if the <code>type</code> equals <code>null</code></li>
123 * <li>if the name of <code>type</code> equals <code>null</code>
125 * <li>if the name of the package of <code>type</code> equals
126 * <code>null</code></li>
129 public static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
130 final Map<String, String> imports) {
131 checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be "
133 checkArgument(parentGenType.getName() != null, "Parent Generated Type name cannot be NULL!");
134 checkArgument(parentGenType.getPackageName() != null,
135 "Parent Generated Type cannot have Package Name referenced as NULL!");
136 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
138 checkArgument(type.getName() != null, "Type name cannot be NULL!");
139 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
141 final String typeName = type.getName();
142 final String typePackageName = type.getPackageName();
143 final String parentTypeName = parentGenType.getName();
144 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
147 if (!imports.containsKey(typeName)) {
148 imports.put(typeName, typePackageName);
150 if (type instanceof ParameterizedType) {
151 final ParameterizedType paramType = (ParameterizedType) type;
152 final Type[] params = paramType.getActualTypeArguments();
153 if (params != null) {
154 for (Type param : params) {
155 putTypeIntoImports(parentGenType, param, imports);
162 * Checks if the constant with the name <code>constName</code> is in the
163 * list of the constant definition for <code>genTO</code>.
166 * string with the name of constant which is sought
168 * generated transfer object in which is <code>constName</code>
170 * @return boolean value
172 * <li>true - if <code>constName</code> is in the list of the
173 * constant definition for <code>genTO</code></li>
174 * <li>false - in other cases</li>
176 * @throws IllegalArgumentException
178 * <li>if <code>constName</code> equals <code>null</code></li>
179 * <li>if <code>genTO</code> equals <code>null</code></li>
182 public static boolean isConstantInTO(String constName, GeneratedTransferObject genTO) {
183 if (constName == null || genTO == null) {
184 throw new IllegalArgumentException();
186 List<Constant> consts = genTO.getConstantDefinitions();
187 for (Constant cons : consts) {
188 if (cons.getName().equals(constName)) {
196 * Creates the map which maps the type name to package name and contains
197 * only package names for enclosed types of <code>genType</code> and
198 * recursivelly their enclosed types.
201 * JAVA <code>Type</code> for which is the map created
202 * @return map of the package names for all the enclosed types and
203 * recursivelly their enclosed types
205 public static Map<String, String> createChildImports(GeneratedType genType) {
206 Map<String, String> childImports = new LinkedHashMap<>();
207 List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
208 if (!childGeneratedTypes.isEmpty()) {
209 for (GeneratedType genTypeChild : childGeneratedTypes) {
210 createChildImports(genTypeChild);
211 childImports.put(genTypeChild.getName(), genTypeChild.getPackageName());
218 * Builds the string which contains either the full path to the type
219 * (package name with type) or only type name if the package is among
220 * <code>imports</code>.
222 * @param parentGenType
223 * generated type which contains <code>type</code>
225 * JAVA <code>Type</code> for which is the string with type info
228 * map of necessary imports for <code>parentGenType</code>
229 * @return string with type name for <code>type</code> in the full format or
230 * in the short format
231 * @throws IllegalArgumentException
233 * <li>if the <code>type</code> equals <code>null</code></li>
234 * <li>if the name of the <code>type</code> equals
235 * <code>null</code></li>
236 * <li>if the name of the package of the <code>type</code>
237 * equals <code>null</code></li>
238 * <li>if the <code>imports</code> equals <code>null</code></li>
241 public static String getExplicitType(final GeneratedType parentGenType, final Type type,
242 final Map<String, String> imports) {
244 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
245 checkArgument(type.getName() != null, "Type name cannot be NULL!");
246 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
247 checkArgument(imports != null, "Imports Map cannot be NULL!");
249 final String typePackageName = type.getPackageName();
250 final String typeName = type.getName();
251 final String importedPackageName = imports.get(typeName);
252 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.startsWith("java.lang")) {
262 builder.append(type.getName());
264 if (!typePackageName.isEmpty()) {
265 builder.append(typePackageName + Constants.DOT + type.getName());
267 builder.append(type.getName());
270 if (type.equals(Types.voidType())) {
273 addActualTypeParameters(builder, type, parentGenType, imports);
275 return builder.toString();
280 * Adds actual type parameters from <code>type</code> to
281 * <code>builder</code> if <code>type</code> is
282 * <code>ParametrizedType</code>.
285 * string builder which contains type name
287 * JAVA <code>Type</code> for which is the string with type info
289 * @param parentGenType
290 * generated type which contains <code>type</code>
292 * map of necessary imports for <code>parentGenType</code>
293 * @return if <code>type</code> is of the type <code>ParametrizedType</code> <br />
294 * <li>then <code>builder</code> + actual <code>type</code>
295 * parameters</li> <li>else only <code>builder</code></li>
297 private static StringBuilder addActualTypeParameters(StringBuilder builder, final Type type,
298 final GeneratedType parentGenType, final Map<String, String> imports) {
299 if (type instanceof ParameterizedType) {
300 final ParameterizedType pType = (ParameterizedType) type;
301 final Type[] pTypes = pType.getActualTypeArguments();
303 builder.append(getParameters(parentGenType, pTypes, imports));
310 * Generates the string with all actual type parameters from
311 * <code>pTypes</code>
313 * @param parentGenType
314 * generated type for which is the JAVA code generated
316 * array of <code>Type</code> instances = actual type parameters
317 * @param availableImports
318 * map of imports for <code>parentGenType</code>
319 * @return string with all actual type parameters from <code>pTypes</code>
321 private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
322 Map<String, String> availableImports) {
323 if (pTypes == null || pTypes.length == 0) {
326 final StringBuilder builder = new StringBuilder();
327 for (int i = 0; i < pTypes.length; i++) {
328 final Type t = pTypes[i];
330 String separator = COMMA;
331 if (i == (pTypes.length - 1)) {
335 String wildcardParam = "";
336 if (t.equals(Types.voidType())) {
337 builder.append("java.lang.Void" + separator);
341 if (t instanceof WildcardType) {
342 wildcardParam = "? extends ";
345 builder.append(wildcardParam + getExplicitType(parentGenType, t, availableImports) + separator);
348 return builder.toString();
352 * Returns the reference to highest (top parent) Generated Transfer Object.
354 * @param childTransportObject
355 * is generated transfer object which can be extended by other
356 * generated transfer object
357 * @return in first case that <code>childTransportObject</code> isn't
358 * extended then <code>childTransportObject</code> is returned. In
359 * second case the method is recursive called until first case.
360 * @throws IllegalArgumentException
361 * if <code>childTransportObject</code> equals <code>null</code>
363 public static GeneratedTransferObject getTopParrentTransportObject(GeneratedTransferObject childTransportObject) {
364 if (childTransportObject == null) {
365 throw new IllegalArgumentException("Parameter childTransportObject can't be null.");
367 if (childTransportObject.getSuperType() == null) {
368 return childTransportObject;
370 return getTopParrentTransportObject(childTransportObject.getSuperType());
375 * Selects from input list of properties only those which have read only
376 * attribute set to true.
379 * list of properties of generated transfer object
380 * @return subset of <code>properties</code> which have read only attribute
383 public static List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(List<GeneratedProperty> properties) {
384 List<GeneratedProperty> readOnlyProperties = new ArrayList<GeneratedProperty>();
385 if (properties != null) {
386 for (final GeneratedProperty property : properties) {
387 if (property.isReadOnly()) {
388 readOnlyProperties.add(property);
392 return readOnlyProperties;
396 * Returns the list of the read only properties of all extending generated
397 * transfer object from <code>genTO</code> to highest parent generated
401 * generated transfer object for which is the list of read only
402 * properties generated
403 * @return list of all read only properties from actual to highest parent
404 * generated transfer object. In case when extension exists the
405 * method is recursive called.
407 public static List<GeneratedProperty> getPropertiesOfAllParents(GeneratedTransferObject genTO) {
408 List<GeneratedProperty> propertiesOfAllParents = new ArrayList<GeneratedProperty>();
409 if (genTO.getSuperType() != null) {
410 final List<GeneratedProperty> allPropertiesOfTO = genTO.getSuperType().getProperties();
411 List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
412 propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
413 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType()));
415 return propertiesOfAllParents;