
org.nuiton.topia.service.sql.batch.actions.AbstractTablesAction Maven / Gradle / Ivy
package org.nuiton.topia.service.sql.batch.actions;
/*
* #%L
* ObServe Toolkit :: ToPIA Extension
* %%
* Copyright (C) 2008 - 2017 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import java.io.Writer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.persistence.metadata.TopiaMetadataEntity;
import org.nuiton.topia.persistence.support.TopiaSqlWork;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTable;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTables;
import org.nuiton.util.TimeLog;
/**
* Support to create action.
*
* Created on 29/12/15.
*
* @author Tony Chemit - [email protected]
* @since 3.0.1
*/
public abstract class AbstractTablesAction extends AbstractSqlAction {
/** Logger. */
private static final Log log = LogFactory.getLog(AbstractTablesAction.class);
protected AbstractTablesAction(R request, boolean showSql) {
super(request, showSql);
}
protected abstract TopiaSqlTables getTables();
protected abstract void executeOnTable(R request, TopiaSqlTable table, PreparedStatement readStatement) throws SQLException;
@Override
protected final void execute() {
for (TopiaSqlTable table : getTables()) {
long startTable = TimeLog.getTime();
TopiaSqlWork sqlWork = new ReadSqlWork(request, table);
getSourcePersistenceContext().getSqlSupport().doSqlWork(sqlWork);
TIME_LOG.log(startTable, "Executed on table.", table.getFullyTableName());
}
}
protected String generateWildcardArguments(Iterable columnNames) {
StringBuilder argsBuilder = new StringBuilder();
for (String ignored : columnNames) {
argsBuilder.append(", ?");
}
return argsBuilder.substring(2);
}
protected void flush(PreparedStatement writeStatement, Writer writer, String tableName, long index) throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Flush for : " + tableName + " (size: " + index + ")");
}
if (writeStatement != null) {
writeStatement.executeBatch();
writeStatement.clearBatch();
}
if (writer != null) {
flush(writer);
}
}
protected List getColumnNames(ResultSetMetaData readResultTatMetaData, int columnCount, Set authorizedColumnNames) throws SQLException {
List builder = new ArrayList<>(columnCount);
for (int i = 1; i <= columnCount; i++) {
String columnName = readResultTatMetaData.getColumnName(i);
if (authorizedColumnNames == null || authorizedColumnNames.contains(columnName.toLowerCase())) {
builder.add(columnName.toLowerCase());
}
}
return builder;
}
protected List getColumnNames(TopiaMetadataEntity metadataEntity, TopiaSqlTable table, ResultSet readResultSet) throws SQLException {
Set authorizedColumnNames;
if (table.isAssociationTable()) {
authorizedColumnNames = new TreeSet<>();
TopiaMetadataEntity entity = table.getAssociationMetadataEntity();
authorizedColumnNames.addAll(entity.getManyToManyAssociations().entrySet().stream()
.filter(entry -> entry.getValue().equals(metadataEntity.getType()))
.map(entry -> entry.getKey().toLowerCase())
.collect(Collectors.toSet()));
authorizedColumnNames.add(table.getJoinColumnName());
} else {
authorizedColumnNames = metadataEntity.getAllDbColumnNames();
}
ResultSetMetaData readResultSetMetaData = readResultSet.getMetaData();
int columnCount = readResultSetMetaData.getColumnCount();
return getColumnNames(readResultSetMetaData, columnCount, authorizedColumnNames);
}
private static class PreparedStatementWrapper implements AutoCloseable {
private final String sqlCode;
private final PreparedStatement preparedStatement;
private PreparedStatementWrapper(String sqlCode, PreparedStatement preparedStatement) {
this.sqlCode = sqlCode;
this.preparedStatement = preparedStatement;
}
@Override
public void close() throws SQLException {
preparedStatement.close();
}
}
protected class ReadSqlWork implements TopiaSqlWork {
private final R request;
private final TopiaSqlTable table;
public ReadSqlWork(R request, TopiaSqlTable table) {
this.request = request;
this.table = table;
}
@Override
public void execute(Connection connection) throws SQLException {
try (PreparedStatementWrapper readStatementWrapper = createReadStatement(table, connection)) {
PreparedStatement readStatement = readStatementWrapper.preparedStatement;
long t0 = TimeLog.getTime();
readStatement.execute();
TIME_LOG.log(t0, "Read statement", readStatementWrapper.sqlCode);
t0 = TimeLog.getTime();
executeOnTable(request, table, readStatement);
TIME_LOG.log(t0, "Execute on table", readStatementWrapper.sqlCode);
}
}
protected PreparedStatementWrapper createReadStatement(TopiaSqlTable table, Connection connection) throws SQLException {
StringBuilder sqlBuilder = new StringBuilder("SELECT " + table.getTableName() + ".*");
sqlBuilder.append(" FROM ").append(table.getFromClause());
for (String joinClause : table.getJoinClauses()) {
sqlBuilder.append(" ").append(joinClause);
}
TopiaSqlTableSelectArgument selectArgument = request.getSelectArgument();
boolean filter = selectArgument != null;
if (filter) {
sqlBuilder.append(" WHERE ").append(table.getWhereClause(selectArgument.getIds()));
}
String sql = sqlBuilder.toString();
if (log.isDebugEnabled()) {
log.debug("Read sql: " + sql);
}
PreparedStatement statement = connection.prepareStatement(sql);
String sqlCode = sql;
if (filter) {
int index = 1;
for (String id : selectArgument.getIds()) {
statement.setString(index++, id);
}
sqlCode = sql + " -> " + selectArgument.getIds();
}
if (showSql) {
log.info(sqlCode);
}
statement.setFetchSize(request.getReadFetchSize());
return new PreparedStatementWrapper(sqlCode, statement);
}
}
}