package org.togglz.core.repository.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import org.togglz.core.activation.UsernameActivationStrategy;
import org.togglz.core.repository.util.MapSerializer;
import org.togglz.core.util.DbUtils;
import org.togglz.core.util.Strings;
/**
* Class that creates and migrates the database table required by {@link JDBCStateRepository}.
*
* @author Christian Kaltepoth
*/
class SchemaUpdater {
private final Connection connection;
private final String tableName;
private final MapSerializer serializer;
protected SchemaUpdater(Connection connection, String tableName, MapSerializer serializer) {
this.connection = connection;
this.tableName = tableName;
this.serializer = serializer;
}
protected boolean doesTableExist() throws SQLException {
return isSuccessful("SELECT * FROM %TABLE%");
}
protected void migrateToVersion1() throws SQLException {
execute("CREATE TABLE %TABLE% (FEATURE_NAME VARCHAR(100) PRIMARY KEY, FEATURE_ENABLED INTEGER, FEATURE_USERS VARCHAR(2000))");
}
protected boolean isSchemaVersion1() throws SQLException {
return columnExists(Columns.FEATURE_NAME) && !columnExists(Columns.STRATEGY_ID);
}
protected void migrateToVersion2() throws SQLException {
/*
* step 1: add new columns
*/
execute("ALTER TABLE %TABLE% ADD STRATEGY_ID VARCHAR(200)");
execute("ALTER TABLE %TABLE% ADD STRATEGY_PARAMS VARCHAR(2000)");
/*
* step 2: migrate the existing data
*/
Statement updateDataStmt = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
try {
ResultSet resultSet = null;
try {
resultSet = updateDataStmt.executeQuery(substitute(
"SELECT FEATURE_NAME, FEATURE_USERS, STRATEGY_ID, STRATEGY_PARAMS FROM %TABLE%"));
while (resultSet.next()) {
// migration is only required if there is data in the users column
String users = resultSet.getString(Columns.FEATURE_USERS);
if (Strings.isNotBlank(users)) {
// convert the user list to the new parameters format
Map<String, String> params = new HashMap<String, String>();
params.put(UsernameActivationStrategy.PARAM_USERS, users);
String paramData = serializer.serialize(params);
resultSet.updateString(Columns.STRATEGY_PARAMS, paramData);
// only overwrite strategy ID if it is not set yet
String strategyId = resultSet.getString(Columns.STRATEGY_ID);
if (Strings.isBlank(strategyId)) {
resultSet.updateString(Columns.STRATEGY_ID, UsernameActivationStrategy.ID);
}
// perform the update
resultSet.updateRow();
}
}
} finally {
DbUtils.closeQuietly(resultSet);
}
} finally {
DbUtils.closeQuietly(updateDataStmt);
}
/*
* step 3: remove the deprecated column
*/
execute("ALTER TABLE %TABLE% DROP COLUMN FEATURE_USERS");
}
/**
* Returns <code>true</code> if the given column exists in the features table.
*
* @throws SQLException
*/
private boolean columnExists(String column) throws SQLException {
return isSuccessful("SELECT " + column + " FROM %TABLE%");
}
/**
* Returns <code>true</code> if the supplied statement returned without any error
*/
private boolean isSuccessful(String sql) throws SQLException {
Statement statement = connection.createStatement();
try {
statement.execute(substitute(sql));
} catch (SQLException e) {
return false;
} finally {
DbUtils.closeQuietly(statement);
}
return true;
}
/**
* Executes the given statement.
*/
private void execute(String sql) throws SQLException {
Statement statement = connection.createStatement();
try {
statement.executeUpdate(substitute(sql));
} finally {
DbUtils.closeQuietly(statement);
}
}
/**
* Replaces <code>%TABLE%</code> with the table name configured.
*/
private String substitute(String s) {
return s.replace("%TABLE%", tableName);
}
}