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));
63 final List<Constant> constants = genType.getConstantDefinitions();
64 final List<MethodSignature> methods = genType.getMethodDefinitions();
67 if (constants != null) {
68 for (final Constant constant : constants) {
69 final Type constantType = constant.getType();
70 putTypeIntoImports(genType, constantType, imports);
75 if (genType instanceof GeneratedTransferObject
76 && isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) {
77 putTypeIntoImports(genType, Types.typeForClass(java.util.regex.Pattern.class), imports);
78 putTypeIntoImports(genType, Types.typeForClass(java.util.Arrays.class), imports);
79 putTypeIntoImports(genType, Types.typeForClass(java.util.ArrayList.class), imports);
83 if (methods != null) {
84 for (final MethodSignature method : methods) {
85 final Type methodReturnType = method.getReturnType();
86 putTypeIntoImports(genType, methodReturnType, imports);
87 for (final MethodSignature.Parameter methodParam : method.getParameters()) {
88 putTypeIntoImports(genType, methodParam.getType(), imports);
90 for (final AnnotationType at : method.getAnnotations()) {
91 putTypeIntoImports(genType, at, imports);
97 if (genType instanceof GeneratedTransferObject) {
98 final GeneratedTransferObject genTO = (GeneratedTransferObject) genType;
99 final List<GeneratedProperty> properties = genTO.getProperties();
100 if (properties != null) {
101 for (GeneratedProperty property : properties) {
102 final Type propertyType = property.getReturnType();
103 putTypeIntoImports(genType, propertyType, imports);
112 * Evaluates if it is necessary to add the package name for
113 * <code>type</code> to the map of imports for <code>parentGenType</code>.
114 * If it is so the package name is saved to the map <code>imports</code>.
116 * @param parentGenType
117 * generated type for which is the map of the necessary imports
120 * JAVA <code>Type</code> for which is the necessary of the
121 * package import evaluated
123 * map of the imports for <code>parentGenType</code>
124 * @throws IllegalArgumentException
126 * <li>if the <code>parentGenType</code> equals
127 * <code>null</code></li>
128 * <li>if the name of <code>parentGenType</code> equals
129 * <code>null</code></li>
130 * <li>if the name of the package of <code>parentGenType</code>
131 * equals <code>null</code></li>
132 * <li>if the <code>type</code> equals <code>null</code></li>
133 * <li>if the name of <code>type</code> equals <code>null</code>
135 * <li>if the name of the package of <code>type</code> equals
136 * <code>null</code></li>
139 public static void putTypeIntoImports(final GeneratedType parentGenType, final Type type,
140 final Map<String, String> imports) {
141 checkArgument(parentGenType != null,
142 "Parent Generated Type parameter MUST be specified and cannot be " + "NULL!");
143 checkArgument(parentGenType.getName() != null, "Parent Generated Type name cannot be NULL!");
144 checkArgument(parentGenType.getPackageName() != null,
145 "Parent Generated Type cannot have Package Name referenced as NULL!");
146 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
148 checkArgument(type.getName() != null, "Type name cannot be NULL!");
149 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
151 final String typeName = type.getName();
152 final String typePackageName = type.getPackageName();
153 final String parentTypeName = parentGenType.getName();
154 final String parentTypePackageName = parentGenType.getPackageName();
155 if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang")
156 || typePackageName.equals(parentTypePackageName) || typePackageName.isEmpty()) {
159 if (!imports.containsKey(typeName)) {
160 imports.put(typeName, typePackageName);
162 if (type instanceof ParameterizedType) {
163 final ParameterizedType paramType = (ParameterizedType) type;
164 final Type[] params = paramType.getActualTypeArguments();
165 if (params != null) {
166 for (Type param : params) {
167 putTypeIntoImports(parentGenType, param, imports);
174 * Checks if the constant with the name <code>constName</code> is in the
175 * list of the constant definition for <code>genTO</code>.
178 * string with the name of constant which is sought
180 * generated transfer object in which is <code>constName</code>
182 * @return boolean value
184 * <li>true - if <code>constName</code> is in the list of the
185 * constant definition for <code>genTO</code></li>
186 * <li>false - in other cases</li>
188 * @throws IllegalArgumentException
190 * <li>if <code>constName</code> equals <code>null</code></li>
191 * <li>if <code>genTO</code> equals <code>null</code></li>
194 public static boolean isConstantInTO(String constName, GeneratedTransferObject genTO) {
195 if (constName == null || genTO == null) {
196 throw new IllegalArgumentException();
198 List<Constant> consts = genTO.getConstantDefinitions();
199 for (Constant cons : consts) {
200 if (cons.getName().equals(constName)) {
208 * Creates the map which maps the type name to package name and contains
209 * only package names for enclosed types of <code>genType</code> and
210 * recursivelly their enclosed types.
213 * JAVA <code>Type</code> for which is the map created
214 * @return map of the package names for all the enclosed types and
215 * recursivelly their enclosed types
217 public static Map<String, String> createChildImports(GeneratedType genType) {
218 Map<String, String> childImports = new LinkedHashMap<>();
219 List<GeneratedType> childGeneratedTypes = genType.getEnclosedTypes();
220 if (!childGeneratedTypes.isEmpty()) {
221 for (GeneratedType genTypeChild : childGeneratedTypes) {
222 createChildImports(genTypeChild);
223 childImports.put(genTypeChild.getName(), genTypeChild.getPackageName());
230 * Builds the string which contains either the full path to the type
231 * (package name with type) or only type name if the package is among
232 * <code>imports</code>.
234 * @param parentGenType
235 * generated type which contains <code>type</code>
237 * JAVA <code>Type</code> for which is the string with type info
240 * map of necessary imports for <code>parentGenType</code>
241 * @return string with type name for <code>type</code> in the full format or
242 * in the short format
243 * @throws IllegalArgumentException
245 * <li>if the <code>type</code> equals <code>null</code></li>
246 * <li>if the name of the <code>type</code> equals
247 * <code>null</code></li>
248 * <li>if the name of the package of the <code>type</code>
249 * equals <code>null</code></li>
250 * <li>if the <code>imports</code> equals <code>null</code></li>
253 public static String getExplicitType(final GeneratedType parentGenType, final Type type,
254 final Map<String, String> imports) {
256 checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!");
257 checkArgument(type.getName() != null, "Type name cannot be NULL!");
258 checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!");
259 checkArgument(imports != null, "Imports Map cannot be NULL!");
261 final String typePackageName = type.getPackageName();
262 final String typeName = type.getName();
263 final String importedPackageName = imports.get(typeName);
264 final StringBuilder builder;
265 if (typePackageName.equals(importedPackageName) || typePackageName.equals(parentGenType.getPackageName())) {
266 builder = new StringBuilder(type.getName());
267 addActualTypeParameters(builder, type, parentGenType, imports);
268 if (builder.toString().equals("Void")) {
272 builder = new StringBuilder();
273 if (typePackageName.startsWith("java.lang")) {
274 builder.append(type.getName());
276 if (!typePackageName.isEmpty()) {
277 builder.append(typePackageName + Constants.DOT + type.getName());
279 builder.append(type.getName());
282 if (type.equals(Types.voidType())) {
285 addActualTypeParameters(builder, type, parentGenType, imports);
287 return builder.toString();
292 * Adds actual type parameters from <code>type</code> to
293 * <code>builder</code> if <code>type</code> is
294 * <code>ParametrizedType</code>.
297 * string builder which contains type name
299 * JAVA <code>Type</code> for which is the string with type info
301 * @param parentGenType
302 * generated type which contains <code>type</code>
304 * map of necessary imports for <code>parentGenType</code>
305 * @return if <code>type</code> is of the type <code>ParametrizedType</code> <br />
306 * <li>then <code>builder</code> + actual <code>type</code>
307 * parameters</li> <li>else only <code>builder</code></li>
309 private static StringBuilder addActualTypeParameters(StringBuilder builder, final Type type,
310 final GeneratedType parentGenType, final Map<String, String> imports) {
311 if (type instanceof ParameterizedType) {
312 final ParameterizedType pType = (ParameterizedType) type;
313 final Type[] pTypes = pType.getActualTypeArguments();
315 builder.append(getParameters(parentGenType, pTypes, imports));
322 * Generates the string with all actual type parameters from
323 * <code>pTypes</code>
325 * @param parentGenType
326 * generated type for which is the JAVA code generated
328 * array of <code>Type</code> instances = actual type parameters
329 * @param availableImports
330 * map of imports for <code>parentGenType</code>
331 * @return string with all actual type parameters from <code>pTypes</code>
333 private static String getParameters(final GeneratedType parentGenType, final Type[] pTypes,
334 Map<String, String> availableImports) {
335 if (pTypes == null || pTypes.length == 0) {
338 final StringBuilder builder = new StringBuilder();
339 for (int i = 0; i < pTypes.length; i++) {
340 final Type t = pTypes[i];
342 String separator = COMMA;
343 if (i == (pTypes.length - 1)) {
347 String wildcardParam = "";
348 if (t.equals(Types.voidType())) {
349 builder.append("java.lang.Void" + separator);
353 if (t instanceof WildcardType) {
354 wildcardParam = "? extends ";
357 builder.append(wildcardParam + getExplicitType(parentGenType, t, availableImports) + separator);
360 return builder.toString();
364 * Returns the reference to highest (top parent) Generated Transfer Object.
366 * @param childTransportObject
367 * is generated transfer object which can be extended by other
368 * generated transfer object
369 * @return in first case that <code>childTransportObject</code> isn't
370 * extended then <code>childTransportObject</code> is returned. In
371 * second case the method is recursive called until first case.
372 * @throws IllegalArgumentException
373 * if <code>childTransportObject</code> equals <code>null</code>
375 public static GeneratedTransferObject getTopParrentTransportObject(GeneratedTransferObject childTransportObject) {
376 if (childTransportObject == null) {
377 throw new IllegalArgumentException("Parameter childTransportObject can't be null.");
379 if (childTransportObject.getSuperType() == null) {
380 return childTransportObject;
382 return getTopParrentTransportObject(childTransportObject.getSuperType());
387 * Selects from input list of properties only those which have read only
388 * attribute set to true.
391 * list of properties of generated transfer object
392 * @return subset of <code>properties</code> which have read only attribute
395 public static List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(List<GeneratedProperty> properties) {
396 List<GeneratedProperty> readOnlyProperties = new ArrayList<GeneratedProperty>();
397 if (properties != null) {
398 for (final GeneratedProperty property : properties) {
399 if (property.isReadOnly()) {
400 readOnlyProperties.add(property);
404 return readOnlyProperties;
408 * Returns the list of the read only properties of all extending generated
409 * transfer object from <code>genTO</code> to highest parent generated
413 * generated transfer object for which is the list of read only
414 * properties generated
415 * @return list of all read only properties from actual to highest parent
416 * generated transfer object. In case when extension exists the
417 * method is recursive called.
419 public static List<GeneratedProperty> getPropertiesOfAllParents(GeneratedTransferObject genTO) {
420 List<GeneratedProperty> propertiesOfAllParents = new ArrayList<GeneratedProperty>();
421 if (genTO.getSuperType() != null) {
422 final List<GeneratedProperty> allPropertiesOfTO = genTO.getSuperType().getProperties();
423 List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
424 propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
425 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType()));
427 return propertiesOfAllParents;