/*
* Copyright (c) 2016 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.runtime.upgrade.support;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.sql.DataSource;
import org.obiba.runtime.Version;
import org.obiba.runtime.upgrade.InstallStep;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import liquibase.change.ColumnConfig;
import liquibase.change.ConstraintsConfig;
import liquibase.change.CreateTableChange;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.sql.visitor.SqlVisitor;
import liquibase.exception.JDBCException;
public class VersionTableInstallStep implements InstallStep {
private static final Logger log = LoggerFactory.getLogger(VersionTableInstallStep.class);
public static final String TABLE_NAME = "version";
private String description = "Create version table.";
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String getDescription() {
return description;
}
/**
* Creates the <code>version</code> table used to keep track of the currently installed version.
* <p>
* This method is called in the case of a new installation (in which the table would be missing).
* </p>
*/
@Override
public void execute(Version currentVersion) {
log.info("Creating version table...");
jdbcTemplate.execute(new ConnectionCallback<Object>() {
@Override
public Object doInConnection(Connection connection) throws SQLException, DataAccessException {
// Find an appropriate database instance for the connection.
Database database = null;
try {
DatabaseFactory databaseFactory = DatabaseFactory.getInstance();
database = databaseFactory.findCorrectDatabaseImplementation(connection);
} catch(JDBCException ex) {
throw new RuntimeException("Could not create version table", ex);
}
// Create the version table.
try {
List<SqlVisitor> sqlVisitors = new ArrayList<SqlVisitor>();
sqlVisitors.add(new CreateInnoDBTableSqlVisitor());
doBuildCreateVersionTableChange().executeStatements(database, sqlVisitors);
log.info("Successfully created the version table.");
} catch(Exception ex) {
throw new RuntimeException("Could not create version table", ex);
}
return null;
}
private CreateTableChange doBuildCreateVersionTableChange() {
CreateTableChange createVersionTable = new CreateTableChange();
createVersionTable.setTableName(TABLE_NAME);
createVersionTable.addColumn(createColumn("major", "java.sql.Types.INTEGER", false));
createVersionTable.addColumn(createColumn("minor", "java.sql.Types.INTEGER", false));
createVersionTable.addColumn(createColumn("micro", "java.sql.Types.INTEGER", false));
createVersionTable.addColumn(createColumn("qualifier", "java.sql.Types.VARCHAR(50)", true));
createVersionTable.addColumn(createColumn("version_string", "java.sql.Types.VARCHAR(50)", false));
return createVersionTable;
}
private ColumnConfig createColumn(String columnName, String columnType, boolean nullable) {
ColumnConfig column = new ColumnConfig();
column.setName(columnName);
column.setType(columnType);
ConstraintsConfig constraints = new ConstraintsConfig();
constraints.setNullable(nullable);
column.setConstraints(constraints);
return column;
}
});
}
private static class CreateInnoDBTableSqlVisitor implements SqlVisitor {
@Override
public String getTagName() {
return "createInnoDBTableSqlVisitor";
}
@Override
public void setApplicableDbms(@SuppressWarnings("rawtypes") Collection applicableDbms) {
// no-op
}
@Override
public boolean isApplicable(Database database) {
return "mysql".equals(database.getTypeName());
}
@Override
public String modifySql(String sql, Database database) {
return sql.toUpperCase().startsWith("CREATE TABLE") ? sql + " ENGINE=InnoDB" : sql;
}
}
}