org.jtalks.poulpe.util.databasebackup.persistence.DbTableData.java Source code

Java tutorial

Introduction

Here is the source code for org.jtalks.poulpe.util.databasebackup.persistence.DbTableData.java

Source

/**
 * Copyright (C) 2011  JTalks.org Team
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library 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
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jtalks.poulpe.util.databasebackup.persistence;

import org.apache.commons.lang.Validate;
import org.jtalks.poulpe.util.databasebackup.domain.ColumnMetaData;
import org.jtalks.poulpe.util.databasebackup.domain.Row;
import org.jtalks.poulpe.util.databasebackup.exceptions.RowProcessingException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The class is responsible for providing table structure and table data.
 * 
 * @author Evgeny Surovtsev
 * 
 */
class DbTableData {
    /**
     * Constructs a new instance of the class with given DataSource and TableName. These parameters will be used for
     * preparing table's structure and data.
     * 
     * @param dataSource
     *            a DataSource object for accessing the table.
     * @param tableName
     *            a name of the table to be dumped.
     */
    public DbTableData(DataSource dataSource, String tableName) {
        Validate.notNull(dataSource, "dataSource parameter must not be null.");
        Validate.notEmpty(tableName, "tableName parameter must not be empty.");
        this.dataSource = dataSource;
        this.tableName = tableName;

        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

    /**
     * The method prepares table's data in the shape and passes every {@link Row} into given RowProcessor.
     * 
     * @param processor
     *            injected logic to perform some actions under passing rows. see details for {@link RowProcessor}.
     * @throws SQLException
     *             if any errors during work with database occur.
     */
    public void getData(final RowProcessor processor) throws SQLException {
        try {
            jdbcTemplate.query(SELECT_FROM + tableName, new RowCallbackHandler() {
                @Override
                public void processRow(ResultSet rs) throws SQLException {
                    ResultSetMetaData metaData = rs.getMetaData();
                    int columnCount = metaData.getColumnCount();

                    Row row = new Row();
                    for (int i = 1; i <= columnCount; i++) {
                        ColumnMetaData columnMetaData = ColumnMetaData.getInstance(metaData.getColumnName(i),
                                SqlTypes.getSqlTypeByJdbcSqlType(metaData.getColumnType(i)));
                        row.addCell(columnMetaData, rs.getObject(i));
                    }
                    try {
                        processor.process(row);
                    } catch (RowProcessingException e) {
                        throw new SQLException(e);
                    }
                }
            });

        } catch (DataAccessException e) {
            throw new SQLException(e);
        }
    }

    /**
     * Returns the structure of the table in the shape of list of Table columns.
     * 
     * @return A list of Table column elements.
     * @throws SQLException
     *             Is thrown in case any errors during work with database occur.
     */
    public List<ColumnMetaData> getStructure() throws SQLException {
        List<ColumnMetaData> tableColumnList = new ArrayList<ColumnMetaData>();
        Statement stmt = null;
        ResultSet rs = null;
        ResultSetMetaData rsmd = null;
        Connection connection = null;
        try {
            // Get a list of defaults for the column
            // this cannot be done via ResultSetMetaData, so doing this via tableMetaData instead
            connection = dataSource.getConnection();
            DatabaseMetaData dbMetaData = connection.getMetaData();
            Map<String, String> columnDefaultValues = getColumnDefaults(dbMetaData);

            // Taking the rest of information from ResultSetMetaData object
            stmt = connection.createStatement();
            // WHERE 1 = 0 -- we don't need actual data, just a table structure, so lets make the query's result empty.
            rs = stmt.executeQuery(SELECT_FROM + tableName + " WHERE 1 = 0");
            rsmd = rs.getMetaData();
            int numberOfColumns = rsmd.getColumnCount();

            for (int i = 1; i <= numberOfColumns; i++) {
                tableColumnList.add(getColumnMetaData(rsmd, columnDefaultValues, i));
            }

        } finally {
            if (stmt != null) {
                stmt.close();
            }
            if (connection != null) {
                connection.close();
            }

        }
        return tableColumnList;
    }

    /**
     * Constructs a new ColumnMetaData objects from given ResultSetMetaData with provided column default values map and
     * the object's index.
     * 
     * @param rsmd
     *            A ResultSetMetaData which contains meta information about all columns for the table.
     * @param columnDefaultValues
     *            A map of possibly defined values by default for columns.
     * @param i
     *            Index of column which should be constructed.
     * @return A constructed ColumnMetaData object.
     * @throws SQLException
     *             Is thrown in case any errors during work with database occur.
     */
    private ColumnMetaData getColumnMetaData(ResultSetMetaData rsmd, Map<String, String> columnDefaultValues, int i)
            throws SQLException {
        SqlTypes columnType = SqlTypes.getSqlTypeByJdbcSqlType(rsmd.getColumnType(i));

        ColumnMetaData column = ColumnMetaData.getInstance(rsmd.getColumnName(i), columnType)
                .setNullable(rsmd.isNullable(i) == ResultSetMetaData.columnNullable)
                .setAutoincrement(rsmd.isAutoIncrement(i));
        if (columnDefaultValues.containsKey(rsmd.getColumnName(i))) {
            column.setDefaultValue(columnDefaultValues.get(rsmd.getColumnName(i)));
        }
        if (columnType.isHasSize()) {
            column.setSize(rsmd.getColumnDisplaySize(i));
        }
        return column;
    }

    /**
     * Gets a default values for each of the columns if that values are defined for the columns.
     * 
     * @param dbMetaData
     *            a DatabaseMetaData instance to fetch the information from.
     * @return A map where key is a Column name and value is Column's default.
     * @throws SQLException
     *             Is thrown in case any errors during work with database occur.
     */
    private Map<String, String> getColumnDefaults(final DatabaseMetaData dbMetaData) throws SQLException {
        Map<String, String> columnDefaultValues = new HashMap<String, String>();
        ResultSet tableMetaData = null;
        try {
            tableMetaData = dbMetaData.getColumns(null, null, tableName, "%");

            while (tableMetaData.next()) {
                String defaultValue = tableMetaData.getString("COLUMN_DEF");
                if (defaultValue != null && defaultValue.length() > 0) {
                    columnDefaultValues.put(tableMetaData.getString("COLUMN_NAME"), defaultValue);
                }
            }
        } finally {
            if (tableMetaData != null) {
                tableMetaData.close();
            }
        }
        return columnDefaultValues;
    }

    private final String tableName;
    private final DataSource dataSource;

    private final JdbcTemplate jdbcTemplate;

    private static final String SELECT_FROM = "SELECT * FROM ";
}