// $HeadURL$
// $Id$
//
// Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.
package edu.harvard.med.screensaver.db;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Joiner;
import org.apache.log4j.Logger;
import org.hibernate.Session;
/**
* Utility for manipulating schemas, via Spring+Hibernate.
*
* @author <a mailto="john_sullivan@hms.harvard.edu">John Sullivan</a>
* @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
*/
public class SchemaUtil extends AbstractDAO
{
private static Logger log = Logger.getLogger(SchemaUtil.class);
private UsersDAO _usersDao;
private List<String> _schemaTableNames = new ArrayList<String>();
public void setUsersDao(UsersDAO usersDao)
{
_usersDao = usersDao;
}
/**
* Truncate all the tables in the schema.
*
* @motivation efficient means of wiping the schema clean between running a unit test
*/
public void truncateTables()
{
log.debug("truncating tables for " + makeDataSourceString());
verifyIsTestDatabase();
try {
List<String> tables = getSchemaTableNames();
if (tables.isEmpty()) {
throw new IllegalStateException("schema has not been instantiated in the database");
}
String sql = "TRUNCATE TABLE " + Joiner.on(",").join(tables);
getEntityManager().createNativeQuery(sql).executeUpdate();
}
catch (Exception e) {
log.error("could not truncate tables: " + e);
}
}
/**
* Grant all privileges on all tables to the developers.
* @motivation allow developers to access and modify tables from psql
*/
public void grantDeveloperPermissions()
{
log.info("granting developer permissions for " + makeDataSourceString());
try {
if (getSchemaTableNames().isEmpty()) {
return;
}
String sql = "GRANT ALL ON " + Joiner.on(",").join(getSchemaTableNames()) + " TO ";
List<String> developerECommonsIds = _usersDao.findDeveloperECommonsIds();
if (developerECommonsIds.size() == 0) {
return;
}
for (String eCommonsId : developerECommonsIds) {
sql += eCommonsId + ", ";
}
sql = sql.substring(0, sql.length() - 2);
getEntityManager().createNativeQuery(sql).executeUpdate();
}
catch (Exception e) {
log.error("could not truncate tables or create schema: " + e);
}
}
private String makeDataSourceString()
{
try {
Session session = getHibernateSession();
Connection connection = session.connection();
String connectionUrl = connection.getMetaData().getURL();
String connectionUserName = connection.getMetaData().getUserName();
String dataSourceString = connectionUserName + "@" + connectionUrl;
return dataSourceString;
}
catch (SQLException e) {
log.error("could not determine connection properties");
return "<unknown database connection>";
}
}
/**
* Return true iff the database is fully loaded.
*
* @motivation Prevent dropping fully loaded databases, or truncating their
* tables, since this is a costly mistake.
*/
public void verifyIsTestDatabase()
{
try {
Connection connection = getHibernateSession().connection();
String connectionUrl = connection.getMetaData().getURL();
if (!connectionUrl.contains("test")) {
throw new RuntimeException("attempted to drop non-test database");
}
}
catch (SQLException e) {
log.error("could not determine connection properties");
}
}
private List<String> getSchemaTableNames() throws SQLException
{
if (_schemaTableNames.isEmpty()) {
try {
Connection connection = getHibernateSession().connection();
String url = connection.getMetaData().getURL();
String schemaName = url.substring(url.lastIndexOf('/') + 1);
_schemaTableNames.addAll(getEntityManager().createNativeQuery("SELECT table_name FROM information_schema.tables WHERE table_catalog = ? AND table_schema = 'public'").setParameter(1, schemaName).getResultList());
}
catch (IllegalStateException e) {
log.error("bad illegal state exception", e);
}
}
return _schemaTableNames;
}
}