All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.topia.service.sql.batch.actions.ReplicateTablesAction 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 com.zaxxer.hikari.pool.HikariProxyConnection;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.sql.rowset.serial.SerialBlob;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.topia.persistence.metadata.TopiaMetadataEntity;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTable;
import org.nuiton.topia.service.sql.batch.tables.TopiaSqlTables;
import org.postgresql.PGConnection;
import org.postgresql.jdbc.PgConnection;
import org.postgresql.largeobject.LargeObject;
import org.postgresql.largeobject.LargeObjectManager;

/**
 * Created on 01/01/16.
 *
 * @author Tony Chemit - [email protected]
 * @since 3.0.1
 */
public class ReplicateTablesAction extends AbstractTablesAction {

    public static final String INSERT_STATEMENT = "INSERT INTO %s.%s(%s) VALUES (%%s);\n";
    /**
     * Logger.
     */
    private static final Log log = LogFactory.getLog(ReplicateTablesAction.class);

    public ReplicateTablesAction(ReplicateTablesRequest request, boolean showSql) {
        super(request, showSql);
    }

    @Override
    protected void executeOnTable(ReplicateTablesRequest request, TopiaSqlTable table, PreparedStatement readStatement) throws SQLException {

        TopiaMetadataEntity metadataEntity = table.getMetadataEntity();

        ResultSet readResultSet = readStatement.getResultSet();

        ResultSetMetaData readResultSetMetaData = readResultSet.getMetaData();
        int columnCount = readResultSetMetaData.getColumnCount();

        List columnNames = getColumnNames(metadataEntity, table, readResultSet);

        boolean useBlob = metadataEntity.withBlob();
        boolean useOutputWriter = useOutputWriter();
        boolean useOutputDb = useOutputDb();

        BlobsContainer.Builder blobsBuilder = null;
        if (useBlob) {

            //FIXME On devrait gérer pour plusieurs colonnes
            String columnName = metadataEntity.getBlobProperties().iterator().next();
            blobsBuilder = BlobsContainer.builder(table.getFullyTableName(), columnName);
            registerBlobsContainer(blobsBuilder);
        }
        PreparedStatement writeStatement = null;

        String insertStatementSql = newInsertStatementSql(table, columnNames);

        if (useOutputDb) {

            String arguments = generateWildcardArguments(columnNames);
            String sql = String.format(insertStatementSql, arguments).trim();
            writeStatement = targetConnection.prepareStatement(sql);

        }

        int writeBatchSize = request.getWriteBatchSize();
        String tableName = table.getFullyTableName();

        long index = 0;
        while (readResultSet.next()) {

            if (log.isTraceEnabled()) {
                log.trace("Copy " + readResultSet.getString(1));
            }

            if (useOutputDb) {

                writeStatement.clearParameters();
                int j = 1;
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = readResultSetMetaData.getColumnName(i);
                    if (columnNames.contains(columnName.toLowerCase())) {
                        Object object = readResultSet.getObject(i);
                        writeStatement.setObject(j++, object);
                    }
                }
                writeStatement.addBatch();

            }

            if (useOutputWriter) {

                try {

                    String blobColumn = null;
                    if (useBlob) {
                        blobColumn = metadataEntity.getBlobProperties().iterator().next();
                    }
                    Connection connection = readStatement.getConnection();
                    String arguments = generateSqlArguments(readResultSet, columnNames, blobColumn, blobsBuilder, connection);
                    String sql = String.format(insertStatementSql, arguments);
                    writer.append(sql);

                } catch (IOException e) {
                    throw new RuntimeException("Could not copyRow", e);
                }

            }

            if ((++index % writeBatchSize) == 0) {
                flush(writeStatement, writer, tableName, index);
            }

        }

        flush(writeStatement, writer, tableName, index);

    }

    @Override
    protected TopiaSqlTables getTables() {
        return request.getTables();
    }

    protected String newInsertStatementSql(TopiaSqlTable table, List columnNames) {

        StringBuilder columnNamesBuilder = new StringBuilder();

        String blobColumn = null;
        if (table.getMetadataEntity().withBlob()) {
            blobColumn = table.getMetadataEntity().getBlobProperties().iterator().next();
        }
        for (String columnName : columnNames) {
            if (!columnName.equals(blobColumn)) {
                columnNamesBuilder.append(", ").append(columnName);
            }
        }

        String sql = String.format(INSERT_STATEMENT,
                                   table.getSchemaName(),
                                   table.getTableName(),
                                   columnNamesBuilder.substring(2));
        if (log.isDebugEnabled()) {
            log.debug("Insert sql: " + sql);
        }

        return sql;

    }

    protected String generateSqlArguments(ResultSet readResultSet,
                                          Iterable columnNames,
                                          String blobColumn, BlobsContainer.Builder blobsBuilder,
                                          Connection connection) throws SQLException, IOException {

        String statement = "";

        for (String columnName : columnNames) {

            Object columnValue = readResultSet.getObject(columnName);

            if (columnName.equals(blobColumn)) {

                if (columnValue == null) {
                    continue;
                }

                InputStream stream;
                int size;
                if (columnValue instanceof Long) {

                    PGConnection pgConnection;

                    if (connection instanceof PgConnection) {
                        pgConnection = (PGConnection) connection;
                    }
//                    else if (connection instanceof NewProxyConnection) {
//
//                        NewProxyConnection connection1 = (NewProxyConnection) connection;
//                        try {
//                            Field field = connection1.getClass().getDeclaredField("inner");
//                            field.setAccessible(true);
//                            pgConnection = (PGConnection) field.get(connection1);
//                        } catch (Exception e) {
//                            throw new RuntimeException(e);
//                        }
//
//                    }
                    else if (connection instanceof HikariProxyConnection) {

                        HikariProxyConnection connection1 = (HikariProxyConnection) connection;

                        try {
                            Field field = connection1.getClass().getSuperclass().getDeclaredField("delegate");
                            field.setAccessible(true);
                            pgConnection = (PGConnection) field.get(connection1);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }

                    } else {
                        throw new IllegalStateException("Can't know how to manage connection: " + connection);
                    }

                    LargeObjectManager lobj = pgConnection.getLargeObjectAPI();

                    LargeObject obj = lobj.open((long) columnValue, LargeObjectManager.READ);
                    size = obj.size();
                    stream = obj.getInputStream();

                } else {
                    Blob blob = (Blob) columnValue;

                    stream = blob.getBinaryStream();
                    SerialBlob serialBlob = new SerialBlob(blob);
                    size = (int) serialBlob.length();
                }

                try (ByteArrayOutputStream stringWriter = new ByteArrayOutputStream(size)) {
                    stringWriter.write(stream);
                    String topiaId = readResultSet.getString("topiaId");
                    Objects.nonNull(topiaId);
                    blobsBuilder.addBlob(topiaId, stringWriter.toByteArray());
                    if (log.isInfoEnabled()) {
                        log.info("Add blob: " + topiaId);
                    }
                }

                continue;
            }

            if (columnValue == null) {
                statement += ", NULL";
                continue;
            }

            if (columnValue instanceof String) {
                String stringValue = (String) columnValue;
                statement += ", '" + stringValue.replaceAll("'", "''") + "'";
                continue;
            }

            if (columnValue instanceof Date) {
                statement += ", '" + columnValue + "'";
                continue;
            }

            statement += ", " + columnValue;
        }

        return statement.substring(2);

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy