// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id $
//
package com.salas.bb.persistence.backend.migration;
import com.salas.bb.persistence.backend.HsqlPersistenceManager;
import java.sql.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
/**
* Abstract schema migration class with tools.
*/
public abstract class AbstractSchema implements ISchemaMigrationStep
{
private static final String MSG_FAILED_ADD_COLUMN = "Failed to add column {0} to {1}";
private static final String MSG_FAILED_DROP_COLUMN = "Failed to drop column {0}.{1}";
private static final String MSG_FAILED_QUERY = "Failed to run query {0}";
private static final String MSG_FAILED_UPDATE = "Failed to run update query {0}";
private static final String MSG_FAILED_DROP_CONSTRAINT = "Failed to drop constraint {0}.{1}";
private static final String MSG_FAILED_RENAME_COLUMN = "Failed to rename {0}.{1} to {2}";
private static final String MSG_FAILED_ADD_TABLE = "Failed to add table {0}";
private static final String MSG_FAILED_RENAME_TABLE = "Failed to rename {0} to {2}";
private static final String STMT_ADD_COLUMN = "ALTER TABLE {0} ADD COLUMN {1}";
private static final String STMT_DROP_COLUMN = "ALTER TABLE {0} DROP COLUMN {1}";
private static final String STMT_DROP_CONSTRAINT = "ALTER TABLE {0} DROP CONSTRAINT {1}";
private static final String STMT_RENAME_COLUMN = "ALTER TABLE {0} ALTER COLUMN {1} RENAME TO {2}";
private static final String STMT_RENAME_TABLE = "ALTER TABLE {0} RENAME TO {1}";
/**
* Migrates from some version to the other.
*
* @param con connection to use.
* @param pm persistence manager to use for data operations.
*
* @throws MigrationException in case of any problems with procedure.
*/
public abstract void perform(Connection con, HsqlPersistenceManager pm) throws MigrationException;
/**
* Selects rows from the database.
*
* @param con connection.
* @param query SQL query string.
*
* @return an array of rows.
*
* @throws MigrationException exception.
*/
Object[][] selectRows(Connection con, String query) throws MigrationException
{
List<Object[]> rows = null;
try
{
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(query);
// Get number of columns
ResultSetMetaData md = rs.getMetaData();
int cols = md.getColumnCount();
while (rs.next())
{
if (rows == null) rows = new ArrayList<Object[]>();
Object[] row = new Object[cols];
for (int i = 0; i < cols; i++) row[i] = rs.getObject(i + 1);
rows.add(row);
}
} catch (SQLException e)
{
throw new MigrationException(MessageFormat.format(MSG_FAILED_QUERY, query), e);
}
return rows == null ? new Object[0][] : rows.toArray(new Object[rows.size()][]);
}
/**
* Updates database and return number of updated rows.
*
* @param con connection.
* @param query query to run.
*
* @return number of updated rows.
*
* @throws MigrationException exception.
*/
int update(Connection con, String query) throws MigrationException
{
return update(con, query, null);
}
/**
* Updates database and return number of updated rows.
*
* @param con connection.
* @param query query to run.
* @param failMessage the message to dump on failure.
*
* @return number of updated rows.
*
* @throws MigrationException exception.
*/
int update(Connection con, String query, String failMessage)
throws MigrationException
{
int updated;
try
{
updated = con.createStatement().executeUpdate(query);
} catch (SQLException e)
{
String msg = failMessage;
if (msg == null) msg = MessageFormat.format(MSG_FAILED_UPDATE, query);
throw new MigrationException(msg, e);
}
return updated;
}
/**
* Adds a table.
*
* @param con connection.
* @param def definition.
*
* @throws MigrationException exception.
*/
void addTable(Connection con, String def)
throws MigrationException
{
update(con, def, MessageFormat.format(MSG_FAILED_ADD_TABLE, def));
}
/**
* Adds the column to the table.
*
* @param con connection.
* @param table table.
* @param colDef column definition.
*
* @throws MigrationException exception.
*/
void addColumn(Connection con, String table, String colDef)
throws MigrationException
{
String query = MessageFormat.format(STMT_ADD_COLUMN, table, colDef);
String msg = MessageFormat.format(MSG_FAILED_ADD_COLUMN, colDef, table);
update(con, query, msg);
}
/**
* Drops the column from the table.
*
* @param con connection.
* @param table table.
* @param columnName column definition.
*
* @throws MigrationException exception.
*/
void dropColumn(Connection con, String table, String columnName)
throws MigrationException
{
String query = MessageFormat.format(STMT_DROP_COLUMN, table, columnName);
String msg = MessageFormat.format(MSG_FAILED_DROP_COLUMN, table, columnName);
update(con, query, msg);
}
/**
* Drops constraint.
*
* @param con connection.
* @param table table name.
* @param constraintName constraint name.
*
* @throws MigrationException migration exception.
*/
void dropConstraint(Connection con, String table, String constraintName)
throws MigrationException
{
String query = MessageFormat.format(STMT_DROP_CONSTRAINT, table, constraintName);
String msg = MessageFormat.format(MSG_FAILED_DROP_CONSTRAINT, table, constraintName);
update(con, query, msg);
}
void renameColumn(Connection con, String table, String columnName, String newName)
throws MigrationException
{
String query = MessageFormat.format(STMT_RENAME_COLUMN, table, columnName, newName);
String msg = MessageFormat.format(MSG_FAILED_RENAME_COLUMN, table, columnName, newName);
update(con, query, msg);
}
void renameTable(Connection con, String table, String newName)
throws MigrationException
{
String query = MessageFormat.format(STMT_RENAME_TABLE, table, newName);
String msg = MessageFormat.format(MSG_FAILED_RENAME_TABLE, table, newName);
update(con, query, msg);
}
}