package com.linkedin.thirdeye.datalayer.util;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.linkedin.thirdeye.datalayer.entity.AbstractEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EntityMappingHolder {
private static final Logger LOG = LoggerFactory.getLogger(EntityMappingHolder.class);
//Map<TableName,EntityName>
BiMap<String, String> tableToEntityNameMap = HashBiMap.create();
Map<String, LinkedHashMap<String, ColumnInfo>> columnInfoPerTable = new HashMap<>();
//DB NAME to ENTITY NAME mapping
Map<String, BiMap<String, String>> columnMappingPerTable = new HashMap<>();
public void register(Connection connection, Class<? extends AbstractEntity> entityClass,
String tableName) throws Exception {
tableName = tableName.toLowerCase();
LOG.info("GENERATING MAPPING FOR TABLE:" + tableName);
DatabaseMetaData databaseMetaData = connection.getMetaData();
String catalog = null;
String schemaPattern = null;
String columnNamePattern = null;
LinkedHashMap<String, ColumnInfo> columnInfoMap = new LinkedHashMap<>();
tableToEntityNameMap.put(tableName, entityClass.getSimpleName());
columnMappingPerTable.put(tableName, HashBiMap.<String, String>create());
boolean foundTable = false;
for (String tableNamePattern : new String[] {tableName.toLowerCase(),
tableName.toUpperCase()}) {
try (ResultSet rs =
databaseMetaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern)) {
while (rs.next()) {
foundTable = true;
String columnName = rs.getString(4);
ColumnInfo columnInfo = new ColumnInfo();
columnInfo.columnNameInDB = columnName.toLowerCase();
columnInfo.sqlType = rs.getInt(5);
columnInfoMap.put(columnName.toLowerCase(), columnInfo);
}
}
}
if (!foundTable) {
throw new RuntimeException("Unable to find table:" + tableName);
}
List<Field> fields = new ArrayList<>();
getAllFields(fields, entityClass);
for (String dbColumn : columnInfoMap.keySet()) {
boolean success = false;
for (Field field : fields) {
field.setAccessible(true);
String entityColumn = field.getName();
if (dbColumn.toLowerCase().equals(entityColumn.toLowerCase())) {
success = true;
}
String dbColumnNormalized = dbColumn.replaceAll("_", "").toLowerCase();
String entityColumnNormalized = entityColumn.replaceAll("_", "").toLowerCase();
if (dbColumnNormalized.equals(entityColumnNormalized)) {
success = true;
}
if (success) {
columnInfoMap.get(dbColumn).columnNameInEntity = entityColumn;
columnInfoMap.get(dbColumn).field = field;
LOG.info("Mapped " + dbColumn + " to " + entityColumn);
columnMappingPerTable.get(tableName).put(dbColumn, entityColumn);
break;
}
}
if(!success) {
LOG.error("Unable to map [" + dbColumn + "] to any field in table [" + entityClass
.getSimpleName() + "] !!!");
}
}
columnInfoPerTable.put(tableName, columnInfoMap);
}
public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));
if (type.getSuperclass() != null) {
fields = getAllFields(fields, type.getSuperclass());
}
return fields;
}
}
class ColumnInfo {
String columnNameInDB;
int sqlType;
String columnNameInEntity;
Field field;
}