/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.mdsal.binding.java.api.generator; import static com.google.common.base.Preconditions.checkArgument; import static org.opendaylight.mdsal.binding.java.api.generator.Constants.COMMA; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.opendaylight.mdsal.binding.model.api.AnnotationType; import org.opendaylight.mdsal.binding.model.api.Constant; import org.opendaylight.mdsal.binding.model.api.GeneratedProperty; import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject; import org.opendaylight.mdsal.binding.model.api.GeneratedType; import org.opendaylight.mdsal.binding.model.api.JavaTypeName; import org.opendaylight.mdsal.binding.model.api.MethodSignature; import org.opendaylight.mdsal.binding.model.api.ParameterizedType; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.api.WildcardType; import org.opendaylight.mdsal.binding.model.util.TypeConstants; import org.opendaylight.mdsal.binding.model.util.Types; public final class GeneratorUtil { private GeneratorUtil() { throw new UnsupportedOperationException(); } /** * Returns the map of imports. The map maps the type name to the package name. To the map are added packages * for genType and for all enclosed types, constants, methods (parameter types, return values), * implemented types. * * @param genType generated type for which the map of the imports is created * @return map of the necessary imports * @throws IllegalArgumentException if genType equals null */ static Map createImports(final GeneratedType genType) { if (genType == null) { throw new IllegalArgumentException("Generated Type cannot be NULL!"); } final Map imports = new LinkedHashMap<>(); List childGeneratedTypes = genType.getEnclosedTypes(); if (!childGeneratedTypes.isEmpty()) { for (GeneratedType genTypeChild : childGeneratedTypes) { imports.putAll(createImports(genTypeChild)); } } // REGULAR EXPRESSION if (genType instanceof GeneratedTransferObject && isConstantInTO(TypeConstants.PATTERN_CONSTANT_NAME, (GeneratedTransferObject) genType)) { putTypeIntoImports(genType, Types.typeForClass(java.util.regex.Pattern.class), imports); } final List methods = genType.getMethodDefinitions(); // METHODS if (methods != null) { for (final MethodSignature method : methods) { final Type methodReturnType = method.getReturnType(); putTypeIntoImports(genType, methodReturnType, imports); for (final MethodSignature.Parameter methodParam : method.getParameters()) { putTypeIntoImports(genType, methodParam.getType(), imports); } for (final AnnotationType at : method.getAnnotations()) { putTypeIntoImports(genType, at, imports); } } } // PROPERTIES if (genType instanceof GeneratedTransferObject) { final GeneratedTransferObject genTO = (GeneratedTransferObject) genType; final List properties = genTO.getProperties(); if (properties != null) { for (GeneratedProperty property : properties) { final Type propertyType = property.getReturnType(); putTypeIntoImports(genType, propertyType, imports); } } } return imports; } /** * Evaluates if it is necessary to add the package name for type to the map of imports for * parentGenType. If it is so the package name is saved to the map imports. * * @param parentGenType generated type for which is the map of the necessary imports built * @param type JAVA Type for which is the necessary of the package import evaluated * @param imports map of the imports for parentGenType * @throws IllegalArgumentException *
    *
  • if the parentGenType equals * null
  • *
  • if the name of parentGenType equals * null
  • *
  • if the name of the package of parentGenType * equals null
  • *
  • if the type equals null
  • *
  • if the name of type equals null *
  • *
  • if the name of the package of type equals * null
  • *
*/ static void putTypeIntoImports(final GeneratedType parentGenType, final Type type, final Map imports) { checkArgument(parentGenType != null, "Parent Generated Type parameter MUST be specified and cannot be " + "NULL!"); checkArgument(parentGenType.getName() != null, "Parent Generated Type name cannot be NULL!"); checkArgument(parentGenType.getPackageName() != null, "Parent Generated Type cannot have Package Name referenced as NULL!"); checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!"); checkArgument(type.getName() != null, "Type name cannot be NULL!"); checkArgument(type.getPackageName() != null, "Type cannot have Package Name referenced as NULL!"); final String typeName = type.getName(); final String typePackageName = type.getPackageName(); final String parentTypeName = parentGenType.getName(); if (typeName.equals(parentTypeName) || typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) { return; } if (!imports.containsKey(typeName)) { imports.put(typeName, type.getIdentifier()); } if (type instanceof ParameterizedType) { final ParameterizedType paramType = (ParameterizedType) type; final Type[] params = paramType.getActualTypeArguments(); if (params != null) { for (Type param : params) { putTypeIntoImports(parentGenType, param, imports); } } } } /** * Checks if the constant with the name constName is in the list of the constant definition for * genTO. * * @param constName string with the name of constant which is sought * @param genTO generated transfer object in which is constName sought * @return boolean value *
    *
  • true - if constName is in the list of the * constant definition for genTO
  • *
  • false - in other cases
  • *
* @throws IllegalArgumentException *
    *
  • if constName equals null
  • *
  • if genTO equals null
  • *
*/ static boolean isConstantInTO(final String constName, final GeneratedTransferObject genTO) { if (constName == null || genTO == null) { throw new IllegalArgumentException(); } List consts = genTO.getConstantDefinitions(); for (Constant cons : consts) { if (cons.getName().equals(constName)) { return true; } } return false; } /** * Creates the map which maps the type name to package name and contains only package names for enclosed types * of genType and recursively their enclosed types. * * @param genType JAVA Type for which is the map created * @return map of the package names for all the enclosed types and recursively their enclosed types */ static Map createChildImports(final GeneratedType genType) { Map childImports = new LinkedHashMap<>(); for (GeneratedType genTypeChild : genType.getEnclosedTypes()) { createChildImports(genTypeChild); childImports.put(genTypeChild.getName(), genTypeChild.getPackageName()); } return childImports; } /** * Builds the string which contains either the full path to the type (package name with type) or only type name * if the package is among imports. * * @param parentGenType generated type which contains type * @param type JAVA Type for which is the string with type info generated * @param imports map of necessary imports for parentGenType * @return string with type name for type in the full format or in the short format * @throws IllegalArgumentException *
    *
  • if the type equals null
  • *
  • if the name of the type equals * null
  • *
  • if the name of the package of the type * equals null
  • *
  • if the imports equals null
  • *
*/ static String getExplicitType(final GeneratedType parentGenType, final Type type, final Map imports) { checkArgument(type != null, "Type parameter MUST be specified and cannot be NULL!"); checkArgument(imports != null, "Imports Map cannot be NULL!"); final JavaTypeName importedType = imports.get(type.getName()); final StringBuilder builder = new StringBuilder(); if (type.getIdentifier().equals(importedType)) { builder.append(type.getName()); addActualTypeParameters(builder, type, parentGenType, imports); if (builder.toString().equals("Void")) { return "void"; } } else { if (type.equals(Types.voidType())) { return "void"; } builder.append(type.getFullyQualifiedName()); addActualTypeParameters(builder, type, parentGenType, imports); } return builder.toString(); } /** * Adds actual type parameters from type to builder if type is * ParametrizedType. * * @param builder string builder which contains type name * @param type JAVA Type for which is the string with type info generated * @param parentGenType generated type which contains type * @param imports map of necessary imports for parentGenType * @return if type is of the type ParametrizedType
*
  • then builder + actual type * parameters
  • else only builder
  • */ private static StringBuilder addActualTypeParameters(final StringBuilder builder, final Type type, final GeneratedType parentGenType, final Map imports) { if (type instanceof ParameterizedType) { final ParameterizedType pType = (ParameterizedType) type; final Type[] pTypes = pType.getActualTypeArguments(); builder.append('<').append(getParameters(parentGenType, pTypes, imports)).append('>'); } return builder; } /** * Generates the string with all actual type parameters from pTypes. * * @param parentGenType generated type for which is the JAVA code generated * @param paramTypes array of Type instances = actual type parameters * @param availableImports map of imports for parentGenType * @return string with all actual type parameters from pTypes */ private static String getParameters(final GeneratedType parentGenType, final Type[] paramTypes, final Map availableImports) { if (paramTypes == null || paramTypes.length == 0) { return "?"; } final StringBuilder builder = new StringBuilder(); for (int i = 0; i < paramTypes.length; i++) { final Type t = paramTypes[i]; String separator = COMMA; if (i == paramTypes.length - 1) { separator = ""; } if (Types.voidType().equals(t)) { builder.append("java.lang.Void").append(separator); } else { if (t instanceof WildcardType) { builder.append("? extends "); } builder.append(getExplicitType(parentGenType, t, availableImports)).append(separator); } } return builder.toString(); } /** * Returns the reference to highest (top parent) Generated Transfer Object. * * @param childTransportObject is generated transfer object which can be extended by other generated transfer object * @return in first case that childTransportObject is not extended then * childTransportObject is returned. In second case the method is recursive called until first * case. * @throws IllegalArgumentException if childTransportObject equals null */ static GeneratedTransferObject getTopParentTransportObject(final GeneratedTransferObject childTransportObject) { if (childTransportObject == null) { throw new IllegalArgumentException("Parameter childTransportObject can't be null."); } if (childTransportObject.getSuperType() == null) { return childTransportObject; } return getTopParentTransportObject(childTransportObject.getSuperType()); } /** * Selects from input list of properties only those which have read only attribute set to true. * * @param properties list of properties of generated transfer object * @return subset of properties which have read only attribute set to true */ static List resolveReadOnlyPropertiesFromTO(final List properties) { List readOnlyProperties = new ArrayList<>(); if (properties != null) { for (final GeneratedProperty property : properties) { if (property.isReadOnly()) { readOnlyProperties.add(property); } } } return readOnlyProperties; } /** * Returns the list of the read only properties of all extending generated transfer object from genTO * to highest parent generated transfer object. * * @param genTO generated transfer object for which is the list of read only properties generated * @return list of all read only properties from actual to highest parent generated transfer object. In case when * extension exists the method is recursive called. */ static List getPropertiesOfAllParents(final GeneratedTransferObject genTO) { List propertiesOfAllParents = new ArrayList<>(); if (genTO.getSuperType() != null) { final List allPropertiesOfTO = genTO.getSuperType().getProperties(); List readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO); propertiesOfAllParents.addAll(readOnlyPropertiesOfTO); propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType())); } return propertiesOfAllParents; } }