| /* |
| * Copyright (c) 2013, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // David McCann - 2.6.0 - July 09, 2013 - Initial Implementation |
| package org.eclipse.persistence.tools.metadata.generation; |
| |
| import static org.eclipse.persistence.internal.helper.ClassConstants.Object_Class; |
| import static org.eclipse.persistence.platform.database.oracle.plsql.OraclePLSQLTypes.XMLType; |
| |
| import java.sql.Types; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.tools.oracleddl.metadata.DatabaseType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.FieldType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.NumericType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLCursorType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.ProcedureType; |
| import org.eclipse.persistence.tools.oracleddl.metadata.SizedType; |
| |
| /** |
| * Utility class typically used when constructing JPA/JAXB metadata from a |
| * list of meta-model database types. |
| * |
| */ |
| public class Util { |
| public static final String ARRAY_STR = "ARRAY"; |
| public static final String BIGINT_STR = "BIGINT"; |
| public static final String BINARY_STR = "BINARY"; |
| public static final String BLOB_STR = "BLOB"; |
| public static final String BOOLEAN_STR = "BOOLEAN"; |
| public static final String CHAR_STR = "CHAR"; |
| public static final String CLOB_STR = "CLOB"; |
| public static final String DATE_STR = "DATE"; |
| public static final String DECIMAL_STR = "DECIMAL"; |
| public static final String DOUBLE_STR = "DOUBLE"; |
| public static final String FLOAT_STR = "FLOAT"; |
| public static final String INTEGER_STR = "INTEGER"; |
| public static final String LONG_STR = "LONG"; |
| public static final String LONGRAW_STR = "LONG RAW"; |
| public static final String LONGVARBINARY_STR = "LONGVARBINARY"; |
| public static final String NCHAR_STR = "NCHAR"; |
| public static final String NCLOB_STR = "NCLOB"; |
| public static final String NUMBER_STR = "NUMBER"; |
| public static final String NUMERIC_STR = "NUMERIC"; |
| public static final String NVARCHAR_STR = "NVARCHAR"; |
| public static final String NVARCHAR2_STR = "NVARCHAR2"; |
| public static final String OTHER_STR = "OTHER"; |
| public static final String RAW_STR = "RAW"; |
| public static final String REAL_STR = "REAL"; |
| public static final String ROWID_STR = "ROWID"; |
| public static final String ROWTYPE_STR = "%ROWTYPE"; |
| public static final String SMALLINT_STR = "SMALLINT"; |
| public static final String STRUCT_STR = "STRUCT"; |
| public static final String TIME_STR = "TIME"; |
| public static final String TIMESTAMP_STR = "TIMESTAMP"; |
| public static final String TINYINT_STR = "TINYINT"; |
| public static final String UROWID_STR = "UROWID"; |
| public static final String VARBINARY_STR = "VARBINARY"; |
| public static final String VARCHAR_STR = "VARCHAR"; |
| public static final String VARCHAR2_STR = "VARCHAR2"; |
| public static final String BINARY_INTEGER_STR = "BINARY_INTEGER"; |
| public static final String PLS_INTEGER_STR = "PLS_INTEGER"; |
| public static final String NATURAL_STR = "NATURAL"; |
| public static final String POSITIVE_STR = "POSITIVE"; |
| public static final String SIGNTYPE_STR = "SIGNTYPE"; |
| public static final String BINARY_INTEGER_TYPE_STR = "BinaryInteger"; |
| public static final String PLS_BOOLEAN_TYPE_STR = "PLSQLBoolean"; |
| public static final String PLS_INTEGER_TYPE_STR = "PLSQLInteger"; |
| public static final String NATURAL_TYPE_STR = "Natural"; |
| public static final String POSITIVE_TYPE_STR = "Positive"; |
| public static final String SIGNTYPE_TYPE_STR = "SignType"; |
| |
| public static final String SYS_XMLTYPE_STR = "SYS.XMLTYPE"; |
| public static final String XMLTYPE_STR = "XMLTYPE"; |
| public static final String _TYPE_STR = "_TYPE"; |
| |
| public static final String COMMA = ","; |
| public static final String SINGLE_SPACE = " "; |
| public static final String COMMA_SPACE_STR = COMMA + SINGLE_SPACE; |
| |
| // for CRUD operations |
| public static final String ALL_QUERYNAME = "findAll"; |
| public static final String PK_QUERYNAME = "findByPrimaryKey"; |
| public static final String CREATE_OPERATION_NAME = "create"; |
| public static final String UPDATE_OPERATION_NAME = "update"; |
| public static final String REMOVE_OPERATION_NAME = "delete"; |
| public static final String OPEN_BRACKET = "("; |
| public static final String CLOSE_BRACKET = ")"; |
| public static final String TYPE_STR = "Type"; |
| public static final String SELECT_FROM_STR = "SELECT * FROM "; |
| public static final String WHERE_STR = " WHERE "; |
| public static final String AND_STR = " AND "; |
| public static final String SET_STR = " SET "; |
| public static final String VALUES_STR = " VALUES "; |
| public static final String UPDATE_STR = "UPDATE "; |
| public static final String INSERT_STR = "INSERT INTO "; |
| public static final String DELETE_STR = "DELETE FROM "; |
| public static final String EQUALS_BINDING1_STR = " = ?1"; |
| public static final String EQUALS_BINDING_STR = " = ?"; |
| public static final String QUESTION_STR = "?"; |
| |
| |
| // SQL class names |
| public static final String ARRAY_CLS_STR = "java.sql.Array"; |
| public static final String NCLOB_CLS_STR = "java.sql.NClob"; |
| public static final String OPAQUE_CLS_STR = "java.sql.Struct"; |
| public static final String ROWID_CLS_STR = "java.sql.RowId"; |
| public static final String STRUCT_CLS_STR = "oracle.sql.OPAQUE"; |
| public static final String ORACLE_TIMESTAMP_CLS_STR = "oracle.sql.TIMESTAMP"; |
| |
| // JDK class names |
| static final String ARRAYLIST_CLS_STR = "java.util.ArrayList"; |
| |
| // direction types |
| static final String IN_STR = "IN"; |
| static final String INOUT_STR = "IN_OUT"; |
| static final String OUT_STR = "OUT"; |
| static final String OUT_CURSOR_STR = "OUT_CURSOR"; |
| static final String CURSOR_STR = "CURSOR"; |
| static final String RESULT_STR = "RESULT"; |
| |
| // misc |
| public static final String DOT = "."; |
| public static final String PERCENT = "%"; |
| public static final String UNDERSCORE = "_"; |
| |
| public static final String ITEMS_FLD_STR = "items"; |
| public static final String ITEMS_COL_STR = "ITEMS"; |
| |
| public static final int OPAQUE = 2007; |
| |
| /** |
| * Returns a unqualified entity class name based on a given table or type name. |
| * The returned string will contain an upper case first char, with the |
| * remaining chars in lower case format. |
| */ |
| public static String getUnqualifiedEntityName(String tableName) { |
| String first = tableName.substring(0, 1).toUpperCase(); |
| String rest = tableName.toLowerCase().substring(1); |
| return first.concat(rest); |
| } |
| |
| /** |
| * Returns a entity class name based on a given table or type name. The returned |
| * string will contain an upper case first char, with the remaining chars in |
| * lower case format. The packageName will be prepended to the Entity name |
| * if non-null. |
| */ |
| public static String getEntityName(String tableName, String packageName) { |
| String entityName = getUnqualifiedEntityName(tableName); |
| return packageName == null ? entityName : packageName + DOT + entityName; |
| } |
| |
| /** |
| * Return the JDBC type name for a given type String. |
| */ |
| public static String getJDBCTypeName(String typeName) { |
| // this is inefficient and should be rewritten such that checking is done once only |
| return getJDBCTypeNameFromType(getJDBCTypeFromTypeName(typeName)); |
| } |
| |
| /** |
| * Return the JDBC type (as int) for a given type name. |
| */ |
| public static int getJDBCTypeFromTypeName(String typeName) { |
| if (typeName.equals(NUMERIC_STR)) { |
| return Types.NUMERIC; |
| } |
| if (typeName.equals(VARCHAR_STR) || typeName.equals(VARCHAR2_STR)) { |
| return Types.VARCHAR; |
| } |
| if (typeName.equals(NVARCHAR_STR) || typeName.equals(NVARCHAR2_STR)) { |
| return Types.NVARCHAR; |
| } |
| if (typeName.equals(DATE_STR)) { |
| return Types.DATE; |
| } |
| if (typeName.equals(TIME_STR)) { |
| return Types.TIME; |
| } |
| if (typeName.equals(TIMESTAMP_STR)) { |
| return Types.TIMESTAMP; |
| } |
| if (typeName.equals(DECIMAL_STR)) { |
| return Types.DECIMAL; |
| } |
| if (typeName.equals(INTEGER_STR)) { |
| return Types.INTEGER; |
| } |
| if (typeName.equals(CHAR_STR)) { |
| return Types.CHAR; |
| } |
| if (typeName.equals(NCHAR_STR)) { |
| return Types.NCHAR; |
| } |
| if (typeName.equals(FLOAT_STR)) { |
| return Types.FLOAT; |
| } |
| if (typeName.equals(REAL_STR)) { |
| return Types.REAL; |
| } |
| if (typeName.equals(DOUBLE_STR)) { |
| return Types.DOUBLE; |
| } |
| if (typeName.equals(BINARY_STR)) { |
| return Types.BINARY; |
| } |
| if (typeName.equals(BLOB_STR)) { |
| return Types.BLOB; |
| } |
| if (typeName.equals(CLOB_STR) || |
| typeName.equals(LONG_STR)) { |
| return Types.CLOB; |
| } |
| if (typeName.equals(NCLOB_STR)) { |
| return Types.NCLOB; |
| } |
| if (typeName.equals(RAW_STR) || |
| typeName.equals(LONGRAW_STR)) { |
| return Types.LONGVARBINARY; |
| } |
| if (typeName.equals(ROWID_STR)) { |
| return Types.VARCHAR; |
| } |
| if (typeName.equals(UROWID_STR)) { |
| return Types.VARCHAR; |
| } |
| if (typeName.equals(BIGINT_STR)) { |
| return Types.BIGINT; |
| } |
| if (typeName.equals(STRUCT_STR)) { |
| return Types.STRUCT; |
| } |
| if (typeName.equals(ARRAY_STR)) { |
| return Types.ARRAY; |
| } |
| if (typeName.equals(ROWID_STR)) { |
| return Types.ROWID; |
| } |
| if (typeName.equalsIgnoreCase(XMLTYPE_STR) || |
| typeName.equalsIgnoreCase(SYS_XMLTYPE_STR)) { |
| return Types.VARCHAR; |
| } |
| if (typeName.equals(BOOLEAN_STR) || |
| typeName.equals(INTEGER_STR) || |
| typeName.equals(SMALLINT_STR) || |
| typeName.equals(TINYINT_STR)) { |
| return Types.INTEGER; |
| } |
| return Types.OTHER; |
| } |
| |
| /** |
| * Return the JDBC type name for a given JDBC type code. |
| */ |
| public static String getJDBCTypeNameFromType(int jdbcType) { |
| String typeName = null; |
| switch (jdbcType) { |
| case Types.NUMERIC: |
| typeName = NUMERIC_STR; |
| break; |
| case Types.VARCHAR: |
| typeName = VARCHAR_STR; |
| break; |
| case Types.NVARCHAR: |
| typeName = NVARCHAR_STR; |
| break; |
| case Types.DECIMAL: |
| typeName = DECIMAL_STR; |
| break; |
| case Types.CHAR: |
| typeName = CHAR_STR; |
| break; |
| case Types.NCHAR: |
| typeName = NCHAR_STR; |
| break; |
| case Types.FLOAT: |
| typeName = FLOAT_STR; |
| break; |
| case Types.REAL: |
| typeName = REAL_STR; |
| break; |
| case Types.DOUBLE: |
| typeName = DOUBLE_STR; |
| break; |
| case Types.BINARY: |
| typeName = BINARY_STR; |
| break; |
| case Types.BLOB: |
| typeName = BLOB_STR; |
| break; |
| case Types.CLOB: |
| typeName = CLOB_STR; |
| break; |
| case Types.NCLOB: |
| typeName = NCLOB_STR; |
| break; |
| case Types.VARBINARY : |
| typeName = LONGVARBINARY_STR; |
| break; |
| case Types.LONGVARBINARY: |
| typeName = LONGVARBINARY_STR; |
| break; |
| case Types.DATE: |
| typeName = DATE_STR; |
| break; |
| case Types.TIME: |
| typeName = TIME_STR; |
| break; |
| case Types.TIMESTAMP: |
| typeName = TIMESTAMP_STR; |
| break; |
| case Types.BIGINT: |
| typeName = BIGINT_STR; |
| break; |
| case Types.ARRAY: |
| typeName = ARRAY_STR; |
| break; |
| case Types.STRUCT: |
| typeName = STRUCT_STR; |
| break; |
| case Types.ROWID: |
| typeName = ROWID_STR; |
| break; |
| default: |
| typeName = OTHER_STR; |
| break; |
| } |
| return typeName; |
| } |
| |
| /** |
| * Return the Class name for a given type name using the provided DatabasePlatform. |
| * Object.class.getName() will be returned if the DatabasePlatform returns null. |
| */ |
| public static String getClassNameFromJDBCTypeName(String typeName, DatabasePlatform databasePlatform) { |
| return getClassFromJDBCTypeName(typeName, databasePlatform).getName(); |
| } |
| |
| /** |
| * Return the Class for a given type name using the provided DatabasePlatform. Object.class will |
| * be returned if the DatabasePlatform returns null. |
| */ |
| public static Class<?> getClassFromJDBCTypeName(String typeName, DatabasePlatform databasePlatform) { |
| Class<?> clz = databasePlatform.getClassTypes().get(typeName); |
| if (clz == null) { |
| return Object_Class; |
| } |
| return clz; |
| } |
| |
| /** |
| * Alter the given type name if required. |
| */ |
| protected static String processTypeName(String typeName) { |
| if (!(getJDBCTypeFromTypeName(typeName) == Types.OTHER)) { |
| if (typeName.equals(XMLTYPE_STR)) { |
| typeName = XMLType.name(); |
| } else { |
| // OR Metadata doesn't handle VARCHAR2 |
| if (typeName.equals(VARCHAR2_STR)) { |
| typeName = VARCHAR_STR; |
| } |
| // for BOOLEAN we want to wrap the type in a PLSQLrecord (in ORMetadata.getDatabaseTypeEnum) to |
| // force the appropriate conversion method in PLSQLStoredProcedureCall (declare block, etc) |
| if (!typeName.equals(BOOLEAN_STR)) { |
| typeName = typeName.concat(_TYPE_STR); |
| } |
| } |
| } else { |
| String oPLSQLTypeName = getOraclePLSQLTypeForName(typeName); |
| if (oPLSQLTypeName != null) { |
| typeName = oPLSQLTypeName; |
| } |
| } |
| return typeName; |
| } |
| |
| /** |
| * Returns a Java class name based on a given qualified name. If the name has |
| * a package prepended to it, the the returned string will be in the format |
| * 'packagename.Name', otherwise the format will be 'Name'. For example, given |
| * the name 'test.EMPLOYEE', the method would return the string 'test.Employee'. |
| * |
| */ |
| public static String getGeneratedJavaClassName(String name) { |
| int dotIdx = name.lastIndexOf(DOT); |
| if (dotIdx == -1) { |
| // no package |
| return getGeneratedJavaClassName(name, null); |
| } |
| String packageName = name.substring(0, dotIdx).toLowerCase(); |
| String typeName = name.substring(dotIdx + 1); |
| String first = typeName.substring(0, 1).toUpperCase(); |
| String rest = typeName.toLowerCase().substring(1); |
| return packageName + DOT + first + rest; |
| } |
| |
| /** |
| * Returns a Java class name based on a given name and package. The returned |
| * string will be in the format 'packagename.Name'. For example, given |
| * the name 'EMPLOYEE' and packageName 'TEST', the method would return the |
| * string 'test.Employee'. |
| * |
| */ |
| public static String getGeneratedJavaClassName(String name, String packageName) { |
| String first = name.substring(0, 1).toUpperCase(); |
| String rest = name.toLowerCase().substring(1); |
| return packageName == null || packageName.length() == 0 ? first + rest : packageName.toLowerCase() + DOT + first + rest; |
| } |
| |
| /** |
| * Return a qualified type name for the given DatabaseType. If the type is a |
| * PLSQLType or a PLSQLCursor, and there is a package name available on the |
| * type's parent, a string will be returned in the format 'package.typename'. |
| * Otherwise the type name will be returned. |
| */ |
| public static String getQualifiedTypeName(DatabaseType dbType) { |
| if (dbType.isPLSQLType()) { |
| String packageName = ((PLSQLType) dbType).getParentType().getPackageName(); |
| // for %ROWTYPE we build a record with no package name - need to check for null |
| return packageName != null ? packageName + DOT + dbType.getTypeName() : dbType.getTypeName(); |
| } |
| |
| if (dbType.isPLSQLCursorType()) { |
| // handle cursor |
| PLSQLCursorType cursor = ((PLSQLCursorType) dbType); |
| return cursor.getParentType().getPackageName() + DOT + cursor.getCursorName(); |
| } |
| |
| return dbType.getTypeName(); |
| } |
| |
| /** |
| * Return a qualified compatible type name for the given DatabaseType. If the type is a |
| * PLSQLType, and there is a package name available on the type's parent, a string will |
| * be returned in the format 'package_typename'. Otherwise the type name will be |
| * returned. A compatible type is the JDBC type equivalent of a PL/SQL type. |
| */ |
| public static String getQualifiedCompatibleTypeName(DatabaseType dbType) { |
| String packageName = null; |
| |
| if (dbType.isPLSQLType()) { |
| PLSQLType plsqlType = (PLSQLType) dbType; |
| packageName = plsqlType.getParentType().getPackageName(); |
| } |
| |
| return packageName != null ? packageName + UNDERSCORE + dbType.getTypeName() : dbType.getTypeName(); |
| } |
| |
| |
| /** |
| * Indicates if a given argument type name is considered a PL/SQL scalar |
| * argument, i.e. is one of BOOLEAN, BINARY_INTEGER, PLS_INTEGER, etc. |
| */ |
| public static boolean isArgPLSQLScalar(String argTypeName) { |
| return argTypeName.equals("BOOLEAN") |
| || argTypeName.equals("PLS_INTEGER") |
| || argTypeName.equals("BINARY_INTEGER") |
| || argTypeName.equals("NATURAL") |
| || argTypeName.equals("POSITIVE") |
| || argTypeName.equals("SIGNTYPE"); |
| } |
| |
| /** |
| * Return the Oracle PL/SQL name for a given PL/SQL scalar type. |
| */ |
| public static String getOraclePLSQLTypeForName(String typeName) { |
| if (typeName.equals(BINARY_INTEGER_STR)) |
| return BINARY_INTEGER_TYPE_STR; |
| if (typeName.equals(BOOLEAN_STR)) |
| return PLS_BOOLEAN_TYPE_STR; |
| if (typeName.equals(PLS_INTEGER_STR)) |
| return PLS_INTEGER_TYPE_STR; |
| if (typeName.equals(NATURAL_STR)) |
| return NATURAL_TYPE_STR; |
| if (typeName.equals(POSITIVE_STR)) |
| return POSITIVE_TYPE_STR; |
| if (typeName.equals(SIGNTYPE_STR)) |
| return SIGNTYPE_TYPE_STR; |
| return null; |
| } |
| |
| /** |
| * Return the attribute-type name for a given FieldType. |
| * |
| * For CHAR sized type, java.lang.Character will be returned. |
| * For CHAR non-sized type, java.lang.String will be returned. |
| * For non-CHAR type, the database platform will be used to get the type name. |
| * If the type to be returned is oracle.sql.Timestamp, java.sql.Timestamp will be |
| * returned instead (to handle conversion issue with Oracle11Platform) |
| */ |
| protected static String getAttributeTypeNameForFieldType(FieldType fldType, DatabasePlatform dbPlatform) { |
| String typeName = getJDBCTypeName(fldType.getTypeName()); |
| String attributeType; |
| if (CHAR_STR.equalsIgnoreCase(typeName) && fldType.getEnclosedType().isSizedType()) { |
| SizedType sizedType = (SizedType) fldType.getEnclosedType(); |
| if (sizedType.getSize() == 1) { |
| attributeType = ClassConstants.CHAR.getName(); |
| } else { |
| attributeType = ClassConstants.STRING.getName(); |
| } |
| } else { |
| attributeType = getClassNameFromJDBCTypeName(typeName.toUpperCase(), dbPlatform); |
| } |
| // handle issue with java.sql.Timestamp conversion and Oracle11 platform |
| if (attributeType.contains(ORACLE_TIMESTAMP_CLS_STR)) { |
| attributeType = ClassConstants.TIMESTAMP.getName(); |
| } else if (attributeType.contains(ClassConstants.ABYTE.getName())) { |
| attributeType = ClassConstants.APBYTE.getName(); |
| } |
| return attributeType; |
| } |
| |
| /** |
| * Return the type name to be used for a given database type. The given |
| * DatabaseType's typeName attribute is typically returned, however, in |
| * some cases special handling may be required. For example, in the |
| * case of a NumericType instance, "DECIMAL" should be used for the |
| * type name. |
| */ |
| protected static String getTypeNameForDatabaseType(DatabaseType dataType) { |
| String typeName = dataType.getTypeName(); |
| if (dataType.isNumericType()) { |
| NumericType numericDataType = (NumericType)dataType; |
| if (numericDataType.getScale() > 0) { |
| typeName = DECIMAL_STR; |
| } |
| } |
| return typeName; |
| } |
| |
| /** |
| * Convenience method that detects multiple procedures with the same procedure |
| * name, and updates the overload value on the relevant ProcedureTypes |
| * accordingly. |
| * |
| * The first ProcedureType will have an overload value of 0, the second 1, |
| * and so on. |
| */ |
| protected static void handleOverloading(List<ProcedureType> procedures) { |
| Map<String, List<ProcedureType>> overloadMap = new HashMap<String, List<ProcedureType>>(); |
| for (ProcedureType procedure : procedures) { |
| String procedureName = procedure.getProcedureName(); |
| List<ProcedureType> multipleProcedures = overloadMap.get(procedureName); |
| if (multipleProcedures == null) { |
| multipleProcedures = new ArrayList<ProcedureType>(); |
| overloadMap.put(procedureName, multipleProcedures); |
| } |
| multipleProcedures.add(procedure); |
| } |
| for (List<ProcedureType> procs : overloadMap.values()) { |
| if (procs.size() > 1) { |
| for (int i = 0, len = procs.size(); i < len; i++) { |
| procs.get(i).setOverload(i); |
| } |
| } |
| } |
| |
| } |
| } |