/*==========================================================================*\
| $Id: UpdateSet.java,v 1.3 2010/10/14 18:41:45 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2008 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT 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 Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.dbupdate;
import java.lang.reflect.Method;
import java.sql.*;
import org.apache.log4j.Logger;
// -------------------------------------------------------------------------
/**
* Encapsulates the necessary database schema updates necessary to bring
* any older version of an application's database up to the most current
* supported version. Normally, one concrete subclass would be created
* for each EOModel or "subsystem" that is managed separately. The intent
* is for one subclass to contain information about all possible updates for
* the given EOModel or subsystem, with each version x to version x+1
* transformation isolated in a single method named according to a given
* naming convention.
*
* By convention, a subclass method named updateToVersionX() would take
* a database currently at version X-1 and apply the necessary changes to
* bring it up to version X. Any older version Y could be upgraded by
* successively applying each Y+1, Y+2, Y+3, ..., X-1, X transformation
* in sequence.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.3 $, $Date: 2010/10/14 18:41:45 $
*/
public abstract class UpdateSet
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new UpdateSet object with the given name. The name is
* a unique identifier for this update set, associated with either the
* EOModel(s) or subsystem(s) to which the updates apply. Version
* numbers for different names are maintained separately.
* @param subsystemName the unique identifier for this update set.
*/
public UpdateSet(String subsystemName)
{
name = subsystemName;
}
//~ Public Methods ........................................................
// ----------------------------------------------------------
/**
* Get the unique identifier for this update set.
* @return the unique name
*/
public String subsystemName()
{
return name;
}
// ----------------------------------------------------------
/**
* Get the database to which updates will be applied.
* @return the database
*/
public Database database()
{
return database;
}
// ----------------------------------------------------------
/**
* Set the database to which updates will be applied.
* @param database the database to operate on
*/
public void setDatabase(Database database)
{
this.database = database;
}
// ----------------------------------------------------------
/**
* Get the old version of the database before applying updates.
* @return the old database version
*/
public int startingVersion()
{
return startingVersion;
}
// ----------------------------------------------------------
/**
* Set the old version of the database before applying updates.
* @param version the old database version
*/
public void setStartingVersion(int version)
{
startingVersion = version;
}
// ----------------------------------------------------------
/**
* Determines whether or not this update set is compatible with the
* given version number. This method is used as a way to determine
* when the database has already been updated by an application using
* a newer (potentially incompatible) update set than this one.
*
* @param version The version to check
* @return true if the given version is recognized by this update set
*/
public boolean supportsVersion(int version)
{
return version < 0 || methodForVersion(version) != null;
}
// ----------------------------------------------------------
/**
* Apply the update necessary to upgrade to the given version.
* @param version The version to move to
* @return true if the update is applied, false if no such update exists
*/
public boolean applyUpdateIncrement(int version)
{
Method update = methodForVersion(version);
boolean result = false;
if (update != null)
{
try
{
log.info("applying " + subsystemName()
+ " database update " + version);
update.invoke(this);
result = true;
}
catch (Exception e)
{
log.error("exception trying to update '" + subsystemName()
+ "' to version " + version, e);
throw new com.webobjects.foundation.NSForwardException(e);
}
}
return result;
}
// ----------------------------------------------------------
/**
* Applies any necessary updates from the given set in order to bring
* the database up to the most recent version. The version 0 method
* should bring the database up to a baseline state, creating any
* initial tables and so on. It is declared abstract here to make
* sure that every update set provides at least version 0 support.
* @throws SQLException
*/
public abstract void updateIncrement0() throws SQLException;
//~ Protected Methods .....................................................
// ----------------------------------------------------------
/**
* Creates an index for the specified column in the given table.
* @param tableName The name of the table to index
* @param columnName The name of the column to index on--add a length
* specification in parentheses (SQL-style) for
* text columns.
*/
protected void createIndexFor(String tableName, String columnName)
{
log.info("creating index for table "
+ tableName + " on column " + columnName);
try
{
database().executeSQL("alter table " + tableName
+ " add index (" + columnName + ")");
}
catch (SQLException e)
{
log.error("Unable to create index in table "
+ tableName + " for column spec " + columnName
+ ": " + e.getClass() + ": " + e);
}
}
//~ Private Methods .......................................................
// ----------------------------------------------------------
/**
* Uses reflection to find the method used to update from version
* v-1 to version v.
* @param version The version to update to
* @return the method object, or null if no such method exists
*/
private Method methodForVersion(int version)
{
try
{
return this.getClass().getMethod("updateIncrement" + version);
}
catch (Exception e)
{
return null;
}
}
//~ Instance/static variables .............................................
private String name;
private Database database;
private int startingVersion = -1;
protected static Logger log = Logger.getLogger(UpdateSet.class);
}