package com.txtr.hibernatedelta.model;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.GeneratedValue;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils;
public class HibernateModelUtil {
public static final int MAX_IDENTIFIER_LENGTH = 30;
private HibernateModelUtil() {
}
public static void checkColumnOrTableName(String entityName, String physicalName, String context) {
checkColumnName("entity " + entityName, physicalName, context);
if (OracleKeywords.KEYWORDS.contains(physicalName)) {
throw new IllegalStateException("physical name '" + physicalName + "' of entity " + entityName + " is a keyword: " + context);
}
}
public static void checkColumnName(String origin, String columnName, String context) {
if (columnName.length() > MAX_IDENTIFIER_LENGTH) {
throw new IllegalStateException("physical column name '" + columnName + "' of " + origin + " too long: " + context);
}
if (!columnName.matches("[a-zA-Z_0-9]*")) {
throw new IllegalStateException("physical column name '" + columnName + "' of " + origin + " contains illegal characters: " + context);
}
}
public static void checkColumnNames(String origin, String[] columnNames, String context) {
for (String columnName : columnNames) {
checkColumnName(origin, columnName, context);
}
}
public static void checkFunctionalIndexColumnNames(String origin, String[] columnNames) {
for (String columnName : columnNames) {
checkFunctionalIndexColumnName(origin, columnName);
}
}
private static void checkFunctionalIndexColumnName(String origin, String columnName) {
checkColumnName(origin, removeFunctions(columnName, origin), "");
}
private static String removeFunctions(String columnName, String origin) {
String realColumnName = removeFunction(columnName, origin);
return columnName.equals(realColumnName) ? realColumnName : removeFunction(realColumnName, origin);
}
private static String removeFunction(String columnName, String origin) {
if (StringUtils.startsWithIgnoreCase(columnName, "LOWER(") && StringUtils.endsWith(columnName, ")")) {
return StringUtils.removeEnd(StringUtils.removeStartIgnoreCase(columnName, "LOWER("), ")");
}
if (StringUtils.startsWithIgnoreCase(columnName, "TRIM(") && StringUtils.endsWith(columnName, ")")) {
return StringUtils.removeEnd(StringUtils.removeStartIgnoreCase(columnName, "TRIM("), ")");
}
if (StringUtils.startsWithIgnoreCase(columnName, "SYS.DBMS_LOB.SUBSTR(") && StringUtils.endsWith(columnName, ")")) {
List<String> arguments = extractArguments(StringUtils.substringBeforeLast(StringUtils.removeStartIgnoreCase(columnName, "SYS.DBMS_LOB.SUBSTR("), ")"));
if (arguments.size() != 2) {
throw new IllegalStateException("SYS.DBMS_LOB.SUBSTR must have 2 parameters: " + columnName + " of " + origin);
}
if (!"512".equals(arguments.get(1))) {
throw new IllegalStateException("SYS.DBMS_LOB.SUBSTR length parameter must be 512: " + columnName + " of " + origin);
}
return arguments.get(0);
}
if (StringUtils.startsWithIgnoreCase(columnName, "SUBSTR(") && StringUtils.endsWith(columnName, ")")) {
List<String> arguments = extractArguments(StringUtils.substringBeforeLast(StringUtils.removeStartIgnoreCase(columnName, "SUBSTR("), ")"));
if (arguments.size() != 3) {
throw new IllegalStateException("SUBSTR must have 3 parameters: " + columnName + " of " + origin);
}
if (!"1".equals(arguments.get(1))) {
throw new IllegalStateException("SUBSTR start parameter must be 1: " + columnName + " of " + origin);
}
if (!"512".equals(arguments.get(2))) {
throw new IllegalStateException("SUBSTR end parameter must be 512: " + columnName + " of " + origin);
}
return arguments.get(0);
}
return columnName;
}
private static List<String> extractArguments(String value) {
List<String> result = new ArrayList<String>();
for (String arg : Arrays.asList(StringUtils.split(value, ","))) {
result.add(arg.trim());
}
return result;
}
public static Class<? extends Object> getTableRootClass(Class<? extends Object> entityClass) {
HibernateTableRootFinder finder = new HibernateTableRootFinder();
finder.getTableRootClass(entityClass);
return finder.getResult();
}
public static Class<?> getTableClass(Class<?> entity) {
Class<? extends Object> tableRootClass = getTableRootClass(entity);
if (entity.equals(tableRootClass)) {
return entity;
}
if (getInheritance(tableRootClass) == InheritanceType.SINGLE_TABLE) {
return tableRootClass;
} else {
return entity;
}
}
public static boolean isTableRoot(Class<?> entity) {
return entity.equals(getTableRootClass(entity));
}
public static boolean isTableClass(Class<?> entity) {
return entity.equals(getTableClass(entity));
}
public static InheritanceType getInheritance(Class<?> entity) {
Class<? extends Object> tableClass = getTableRootClass(entity);
Inheritance inheritance = tableClass.getAnnotation(Inheritance.class);
if (inheritance == null) {
throw new IllegalStateException("inheritance type not found: " + entity);
}
return inheritance.strategy();
}
public static String getTableName(Class<?> entity) {
final Table table = entity.getAnnotation(Table.class);
final VirtualRootTable virtualRootTable = entity.getAnnotation(VirtualRootTable.class);
if (table != null) {
return table.name();
} else if (virtualRootTable != null) {
return virtualRootTable.value();
} else {
throw new IllegalArgumentException("not a table annotated class: " + entity);
}
}
public static String getSequenceName(Class<?> entity) {
final Class<?> tableRootClass = getTableRootClass(entity);
if (tableRootClass != null && hasAutoGeneratedId(entity)) {
return buildSequenceName(getTableName(tableRootClass));
} else {
return null;
}
}
private static boolean hasAutoGeneratedId(Class<?> entity) {
for (Field field : entity.getDeclaredFields()) {
if (field.getAnnotation(GeneratedValue.class) != null) {
return true;
}
}
return entity.getSuperclass() != null && hasAutoGeneratedId(entity.getSuperclass());
}
public static String buildSequenceName(String tableName) {
// the table name may already be long and we may not exceed 30 characters
return (tableName + "_").toUpperCase();
}
}