cube-manager/cube-manager/src/main/java/org/gcube/data/analysis/tabulardata/cube/tablemanagers/DefaultTableCreator.java

365 lines
11 KiB
Java

package org.gcube.data.analysis.tabulardata.cube.tablemanagers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.enterprise.event.Event;
import org.gcube.data.analysis.tabulardata.cube.data.DatabaseWrangler;
import org.gcube.data.analysis.tabulardata.cube.data.SQLDatabaseWrangler.RandomString;
import org.gcube.data.analysis.tabulardata.cube.events.TableCreationEvent;
import org.gcube.data.analysis.tabulardata.cube.exceptions.NoSuchTableException;
import org.gcube.data.analysis.tabulardata.cube.exceptions.TableCreationException;
import org.gcube.data.analysis.tabulardata.cube.metadata.CubeMetadataWrangler;
import org.gcube.data.analysis.tabulardata.model.column.Column;
import org.gcube.data.analysis.tabulardata.model.column.factories.IdColumnFactory;
import org.gcube.data.analysis.tabulardata.model.column.type.IdColumnType;
import org.gcube.data.analysis.tabulardata.model.column.type.TimeDimensionColumnType;
import org.gcube.data.analysis.tabulardata.model.datatype.DataType;
import org.gcube.data.analysis.tabulardata.model.idioms.ColumnHasName;
import org.gcube.data.analysis.tabulardata.model.metadata.column.ColumnMetadata;
import org.gcube.data.analysis.tabulardata.model.metadata.column.PeriodTypeMetadata;
import org.gcube.data.analysis.tabulardata.model.metadata.table.TableMetadata;
import org.gcube.data.analysis.tabulardata.model.table.Table;
import org.gcube.data.analysis.tabulardata.model.table.TableType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
public abstract class DefaultTableCreator implements TableCreator {
Event<TableCreationEvent> tableCreatedEvent;
private static Logger logger = LoggerFactory.getLogger(DefaultTableCreator.class);
private static RandomString randomString = new RandomString(6);
protected DatabaseWrangler dbWrangler;
protected CubeMetadataWrangler mdWrangler;
protected TableManager tableManager;
protected List<Column> newTableColumns = Lists.newArrayList();
protected List<Column> newDBColumns = Lists.newArrayList();
// Following attributes are used for cloning
protected Table tableToClone = null;
protected Set<Column> columnsToRemove = Sets.newHashSet();
protected boolean copyData = false;
Map<Column, DataType> columnAlterMap = new HashMap<Column, DataType>();
private TableType tableType;
public DefaultTableCreator(DatabaseWrangler dbWrangler, CubeMetadataWrangler mdWrangler, TableManager tableManager,
TableType tableType, Event<TableCreationEvent> tableCreatedEvent) {
super();
this.dbWrangler = dbWrangler;
this.mdWrangler = mdWrangler;
this.tableManager = tableManager;
this.tableType = tableType;
this.tableCreatedEvent = tableCreatedEvent;
}
@Override
public TableCreator addColumn(Column column) {
checkColumnToAdd(column);
newTableColumns.add(column);
newDBColumns.add(column);
return this;
}
@Override
public TableCreator addColumnAfter(Column columnToAdd, Column columnBefore) {
checkColumnToAdd(columnToAdd);
int index = newTableColumns.indexOf(columnBefore);
if (index==-1) throw new IllegalArgumentException(columnBefore+" not found");
newTableColumns.add(index+1, columnToAdd);
newDBColumns.add(columnToAdd);
return this;
}
@Override
public TableCreator addColumnFirst(Column columnToAdd) {
checkColumnToAdd(columnToAdd);
newTableColumns.add(0, columnToAdd);
newDBColumns.add(columnToAdd);
return this;
}
@Override
public TableCreator addColumnBefore(Column columnToAdd, Column columnAfter) {
checkColumnToAdd(columnToAdd);
int index = newTableColumns.indexOf(columnAfter);
if (index==-1) throw new IllegalArgumentException(columnAfter+" not found");
newTableColumns.add(index, columnToAdd);
newDBColumns.add(columnToAdd);
return this;
}
@Override
public TableCreator addColumns(Column... columns) {
for (Column column : columns) {
addColumn(column);
}
return this;
}
@Override
public TableCreator addColumnsAfter(Column columnBefore, Column... columns) {
for (Column column : columns) {
addColumnAfter(column, columnBefore);
}
return this;
}
@Override
public TableCreator addColumnsBefore(Column columnAfter, Column... columns) {
for (Column column : columns) {
addColumnBefore(column, columnAfter);
}
return this;
}
public TableCreator removeColumn(Column columnToRemove){
removeColumnInternal(columnToRemove);
return this;
}
private void checkColumnToAdd(Column column) {
if (!isAllowedColumn(column))
throw new IllegalArgumentException("Invalid column type: " + column.getColumnType());
}
protected final boolean isAllowedColumn(Column column) {
if (column.getColumnType().equals(new IdColumnType()))
return false;
return true;
}
@Override
public TableCreator like(Table table, boolean copyData) {
return like(table, copyData, new ArrayList<Column>(0));
}
@SuppressWarnings("unchecked")
@Override
public TableCreator like(Table table, boolean copyData, List<Column> columnsToRemove) {
tableToClone = table;
this.copyData = copyData;
newTableColumns = new ArrayList<Column>();
for (Column column : table.getColumnsExceptTypes(IdColumnType.class)){
Column newColumn = new Column(column.getLocalId(), column.getDataType(), column.getColumnType());
newColumn.setName(column.getName());
if (column.hasRelationship())
newColumn.setRelationship(column.getRelationship());
List<ColumnMetadata> metadataToReuse = new ArrayList<ColumnMetadata>();
for (ColumnMetadata metadata : column.getAllMetadata())
if (metadata.isInheritable())
metadataToReuse.add(metadata);
if (!metadataToReuse.isEmpty())
newColumn.setAllMetadata(metadataToReuse);
newTableColumns.add(newColumn);
}
removeColumnsInternal(columnsToRemove);
return this;
}
private void removeColumnsInternal(List<Column> columnsToRemove) {
if (tableToClone==null) return;
this.columnsToRemove = Sets.newHashSet();
for (Column columnToRemove : columnsToRemove) {
removeColumnInternal(columnToRemove);
}
}
private void removeColumnInternal(Column columnToRemove) {
if (tableToClone.getColumns().contains(columnToRemove)) {
this.columnsToRemove.add(columnToRemove);
this.newTableColumns.remove(columnToRemove);
}
}
@Override
public TableCreator changeColumnType(Column column, DataType newType) {
this.columnAlterMap.put(column, newType);
return this;
}
public Table create() throws TableCreationException {
return create(null);
}
@SuppressWarnings("unchecked")
@Override
public Table create(String selectedTableName) throws TableCreationException {
try{
checkConsistency();
setColumnNames();
String tableName = selectedTableName;
if (tableToClone != null) {
//TODO: add clone with new table name
// Handle cloning
tableName = dbWrangler.cloneTable(tableToClone.getName(), copyData, false);
for (Column column : columnsToRemove) {
dbWrangler.removeColumn(tableName, column.getName());
}
for (Column column : newDBColumns) {
dbWrangler.addColumn(tableName, column.getName(), column.getDataType(), column.getCreationDefaultValue());
}
for (Entry<Column, DataType> entry: this.columnAlterMap.entrySet()){
dbWrangler.alterColumnType(tableName, entry.getKey().getName(), entry.getValue());
}
} else {
// Handle simple creation of empty table
if (selectedTableName == null)
tableName = dbWrangler.createTable();
else dbWrangler.createTable(selectedTableName);
for (Column column : newDBColumns) {
dbWrangler.addColumn(tableName, column.getName(), column.getDataType(), column.getCreationDefaultValue());
}
}
Column idColumn = createIdColumn();
if (tableToClone != null)
idColumn.setLocalId(tableToClone.getColumnsByType(IdColumnType.class).get(0).getLocalId());
List<Column> columns = Lists.newArrayList(idColumn);
columns.addAll(getAllColumnsExceptId());
addIndexes(tableName, columns);
Table newTable = createBaseTable(tableName, columns);
// Clone metadata
if (tableToClone != null) {
cloneMetadata(tableToClone, newTable);
}
// Register codelist on metadata DB
Table createdTable = mdWrangler.save(newTable, false);
tableCreatedEvent.fire(new TableCreationEvent(createdTable));
return createdTable;
}catch(TableCreationException tce){
throw tce;
}catch (Exception e) {
e.printStackTrace();
throw new TableCreationException(e.getMessage());
}finally{
resetTableCreator();
}
}
private void resetTableCreator(){
newTableColumns = Lists.newArrayList();
newDBColumns = Lists.newArrayList();
tableToClone = null;
columnsToRemove = Sets.newHashSet();
copyData = false;
}
protected void checkConsistency() throws TableCreationException {
try {
checkColumnsRelationship();
} catch (Exception e) {
throw new TableCreationException(e.getMessage());
}
}
private void checkColumnsRelationship() throws Exception {
for (Column column : getAllColumnsExceptId()) {
if (column.hasRelationship()) {
try {
if (column.getColumnType() instanceof TimeDimensionColumnType && column.contains(PeriodTypeMetadata.class) )
continue;
Table targetTable = tableManager.get(column.getRelationship().getTargetTableId());
targetTable.getColumnById(column.getRelationship().getTargetColumnId());
} catch (NoSuchTableException e) {
throw new Exception(String.format("Referenced Codelist with ID %1$s does not exists.", column
.getRelationship().getTargetTableId()));
}
}
}
}
protected void setColumnNames() {
List<Column> columns = newDBColumns;
for (Column column : columns) {
if (column.hasName()) {
continue;
}
String eligibleName;
do {
eligibleName = ColumnNameGenerator.generateColumnName();
} while (!Collections2.filter(newTableColumns, new ColumnHasName(eligibleName)).isEmpty());
column.setName(eligibleName);
}
}
protected Table createBaseTable(String tableName, List<Column> columns) {
Table result = new Table(tableType);
result.setColumns(columns);
result.setName(tableName);
return result;
}
protected void cloneMetadata(Table sourceTable, Table destTable) {
for (TableMetadata m : sourceTable.getAllMetadata()) {
logger.info("source metadata : "+m);
if (m.isInheritable())
destTable.setMetadata(m);
}
}
private List<Column> getAllColumnsExceptId() {
List<Column> result = Lists.newArrayList(newTableColumns);
if (tableToClone != null)
result.removeAll(tableToClone.getColumnsByType(new IdColumnType()));
for (Column col: result){
DataType type;
if ((type=columnAlterMap.get(col))!=null)
col.setDataType(type);
}
return result;
}
protected abstract void addIndexes(String tableName, Collection<Column> columns);
protected Column createIdColumn() {
return IdColumnFactory.create();
}
public static class ColumnNameGenerator {
public static String generateColumnName() {
return randomString.nextString().toLowerCase();
}
}
}