Java tutorial
/** * 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.ForeignKey; import org.jtalks.poulpe.util.databasebackup.domain.TableKey; import org.jtalks.poulpe.util.databasebackup.domain.UniqueKey; import org.springframework.jdbc.support.JdbcUtils; import org.springframework.jdbc.support.MetaDataAccessException; import javax.sql.DataSource; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * The class is responsible for providing table's keys information. * * @author Evgeny Surovtsev * */ public class DbTableKeys { /** * Constructs a new instance of the class with given DataSource and TableName. These parameters will be used for * getting table's keys information. * * @param dataSource * a DataSource object for accessing the table. * @param tableName * a name of the table to be dumped. */ public DbTableKeys(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; } /** * Obtain from the database a list of tables' unique keys. * * @return A list of {@link UniqueKey} object represented unique keys. * @throws SQLException * Is thrown in case any errors during work with database occur. */ @SuppressWarnings("unchecked") public Set<UniqueKey> getUniqueKeys() throws SQLException { Set<UniqueKey> tableUniqueKeySet = null; try { tableUniqueKeySet = (Set<UniqueKey>) JdbcUtils.extractDatabaseMetaData(dataSource, new KeyListProcessor(tableName, new TableKeyPerformer() { @Override public ResultSet getResultSet(DatabaseMetaData dmd, String tableName) throws SQLException { return dmd.getIndexInfo(null, null, tableName, true, true); } @Override public void addKeyToSet(ResultSet rs, Set<TableKey> keySet) throws SQLException { if (rs.getString(INDEX_NAME) != null && rs.getString(COLUMN_NAME) != null) { UniqueKey key = new UniqueKey(rs.getString(INDEX_NAME), rs.getString(COLUMN_NAME)); if (!isPrimaryKey(key)) { keySet.add(key); } } } })); Map<String, UniqueKey> resultMap = new HashMap<String, UniqueKey>(); for (UniqueKey uniqueKey : tableUniqueKeySet) { if (resultMap.containsKey(uniqueKey.getIndexName())) { Set<String> existingColumns = new HashSet<String>( resultMap.get(uniqueKey.getIndexName()).getColumnNameSet()); existingColumns.addAll(uniqueKey.getColumnNameSet()); resultMap.put(uniqueKey.getIndexName(), new UniqueKey(uniqueKey.getIndexName(), existingColumns)); } else { resultMap.put(uniqueKey.getIndexName(), uniqueKey); } } tableUniqueKeySet.clear(); for (UniqueKey key : resultMap.values()) { tableUniqueKeySet.add(key); } } catch (MetaDataAccessException e) { throw new SQLException(e); } return tableUniqueKeySet; } /** * Obtain from the database a list of tables' primary keys. * * @return A list of {@link UniqueKey} object represented foreign keys. * @throws SQLException * Is thrown in case any errors during work with database occur. */ @SuppressWarnings("unchecked") public Set<UniqueKey> getPrimaryKeys() throws SQLException { if (primaryKeys != null) { return primaryKeys; } Set<UniqueKey> tablePrimaryKeySet = null; try { tablePrimaryKeySet = (Set<UniqueKey>) JdbcUtils.extractDatabaseMetaData(dataSource, new KeyListProcessor(tableName, new TableKeyPerformer() { @Override public ResultSet getResultSet(DatabaseMetaData dmd, String tableName) throws SQLException { return dmd.getPrimaryKeys(null, null, tableName); } @Override public void addKeyToSet(ResultSet rs, Set<TableKey> keySet) throws SQLException { if (rs.getString(PK_NAME) != null && rs.getString(COLUMN_NAME) != null) { keySet.add(new UniqueKey(rs.getString(PK_NAME), rs.getString(COLUMN_NAME))); } } })); } catch (MetaDataAccessException e) { throw new SQLException(e); } primaryKeys = tablePrimaryKeySet; return tablePrimaryKeySet; } /** * Obtains the list of tables foreign keys. * * @return A list of {@link ForeignKey} object represented foreign keys. * @throws SQLException * Is thrown in case any errors during work with database occur. */ @SuppressWarnings("unchecked") public Set<ForeignKey> getForeignKeys() throws SQLException { Set<ForeignKey> tableForeignKeySet = null; try { tableForeignKeySet = (Set<ForeignKey>) JdbcUtils.extractDatabaseMetaData(dataSource, new KeyListProcessor(tableName, new TableKeyPerformer() { @Override public ResultSet getResultSet(DatabaseMetaData dmd, String tableName) throws SQLException { return dmd.getImportedKeys(null, null, tableName); } @Override public void addKeyToSet(ResultSet rs, Set<TableKey> keySet) throws SQLException { if (rs.getString(FK_NAME) != null) { keySet.add(new ForeignKey(rs.getString(FK_NAME), rs.getString(FKCOLUMN_NAME), rs.getString(PKTABLE_NAME), rs.getString(PKCOLUMN_NAME))); } } })); } catch (MetaDataAccessException e) { throw new SQLException(e); } return tableForeignKeySet; } /** * Checks if a given Unique key is a primary key. We need this functionality because primary key is an unique key as * the same time and there is no method to obtain list of unique key which are not primary keys. So for getting that * list we get a list of all unique keys (including primary) and then check every key in the list and remove it if * it is a primary ar the same time. * * @param key * an unique key to perform test upon. * @return true if given unique key is a primary at the same time or false otherwise. * @throws SQLException * if any of errors occur during working with database. */ private boolean isPrimaryKey(UniqueKey key) throws SQLException { // we need primaryKeyList loaded before we get list of unique keys. // because primary key is a unique key as well and we need a way to sort it out. if (primaryKeys == null) { primaryKeys = getPrimaryKeys(); } for (UniqueKey primaryKey : primaryKeys) { if (primaryKey.getIndexName().equals(key.getIndexName())) { return true; } } return false; } private final String tableName; private final DataSource dataSource; private Set<UniqueKey> primaryKeys; private static final String COLUMN_NAME = "COLUMN_NAME"; private static final String INDEX_NAME = "INDEX_NAME"; private static final String PK_NAME = "PK_NAME"; private static final String FK_NAME = "FK_NAME"; private static final String FKCOLUMN_NAME = "FKCOLUMN_NAME"; private static final String PKTABLE_NAME = "PKTABLE_NAME"; private static final String PKCOLUMN_NAME = "PKCOLUMN_NAME"; }