diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java index e3b534737..4cb9d285b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java @@ -147,10 +147,9 @@ public class ConfigurationPropertiesSmokeTests implements connectionProps.put("user", username); connectionProps.put("password", password); - Connection conn = null; - try { - conn = DriverManager.getConnection(url, connectionProps); - closeConnection(conn); + try (Connection conn = DriverManager + .getConnection(url, connectionProps)) { + // Just open the connection and close it. } catch (SQLException e) { ss.fatal(this, "Can't connect to the database: " + PROPERTY_DB_URL + "='" + url + "', " + PROPERTY_DB_USERNAME + "='" @@ -167,26 +166,21 @@ public class ConfigurationPropertiesSmokeTests implements Properties connectionProps, StartupStatus ss, String dbType) { String testString = "ABC\u00CE\u0123"; - Connection conn = null; - Statement stmt = null; - PreparedStatement pstmt = null; - try { - // Get the connection. - conn = DriverManager.getConnection(url, connectionProps); + try (Connection conn = DriverManager + .getConnection(url, connectionProps); + Statement stmt = conn.createStatement()) { // Create the temporary table. - stmt = conn.createStatement(); stmt.executeUpdate("CREATE TEMPORARY TABLE smoke_test (contents varchar(100))"); // Write the test string, encoding in UTF-8 on the way in. - try { - pstmt = conn - .prepareStatement("INSERT INTO smoke_test values ( ? )"); + try (PreparedStatement pstmt = conn + .prepareStatement("INSERT INTO smoke_test values ( ? )")) { pstmt.setBytes(1, testString.getBytes("UTF-8")); + pstmt.executeUpdate(); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } - pstmt.executeUpdate(); // Read it back as a String. Does the database decode it properly? ResultSet rs = stmt.executeQuery("SELECT * FROM smoke_test"); @@ -213,10 +207,6 @@ public class ConfigurationPropertiesSmokeTests implements } } catch (SQLException e) { ss.fatal(this, "Failed to check handling of Unicode characters", e); - } finally { - closeStatement(pstmt); - closeStatement(stmt); - closeConnection(conn); } } @@ -231,32 +221,6 @@ public class ConfigurationPropertiesSmokeTests implements return u.toString(); } - /** - * Close the statement, catching any exception. - */ - private void closeStatement(Statement stmt) { - if (stmt != null) { - try { - stmt.close(); - } catch (SQLException e) { - log.error("Failed to close SQL statement", e); - } - } - } - - /** - * Close the connection, catching any exception. - */ - private void closeConnection(Connection conn) { - if (conn != null) { - try { - conn.close(); - } catch (SQLException e) { - log.error("Failed to close database connection", e); - } - } - } - /** * Confirm that the default namespace is specified and a syntactically valid * URI. It should also end with "/individual/". diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/GuardAgainstUnmigratedRDB.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/GuardAgainstUnmigratedRDB.java new file mode 100644 index 000000000..72eaf09e1 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/GuardAgainstUnmigratedRDB.java @@ -0,0 +1,106 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.servlet.setup; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Properties; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; +import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus; + +/** + * If there are RDB tables in the database that have not been converted to TDB, + * throw an error. + * + * The ConfigurationPropertiesSmokeTests has already run, so we know we can + * access the database. A table named "jena_graph", means that the database + * contains RDB. A table named "vivo_rdb_migrated" means that the conversion + * utility has been run. + */ +public class GuardAgainstUnmigratedRDB implements ServletContextListener { + private static final String PROPERTY_DB_URL = "VitroConnection.DataSource.url"; + private static final String PROPERTY_DB_USERNAME = "VitroConnection.DataSource.username"; + private static final String PROPERTY_DB_PASSWORD = "VitroConnection.DataSource.password"; + + private static final String TABLE_NAME_RDB = "jena_graph"; + private static final String TABLE_NAME_CONVERSION = "vivo_rdb_migrated"; + + private static final String MESSAGE_PROBLEM = "The database at %s" + + " contains data from an earlier VIVO (before 1.7). " + + "It does not appear that this data has been migrated. " + + "The upgrade guide has instructions on migrating " + + "this data to the current VIVO."; + private static final String MESSAGE_TECHNICAL = "More technically: " + + "the database contains tables used by Jena RDB ('jena_graph' and " + + "others). It does not contain the table 'vivo_rdb_migrated', " + + "which is created when the data is migrated to Jena TDB files."; + private static final String MESSAGE_WHAT_NOW = "You must either migrate " + + "the obsolete RDB data or remove it from your database."; + + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + ConfigurationProperties props = ConfigurationProperties.getBean(ctx); + StartupStatus ss = StartupStatus.getBean(ctx); + + String url = props.getProperty(PROPERTY_DB_URL); + String username = props.getProperty(PROPERTY_DB_USERNAME); + String password = props.getProperty(PROPERTY_DB_PASSWORD); + + Properties connectionProps = new Properties(); + connectionProps.put("user", username); + connectionProps.put("password", password); + + try (Connection conn = DriverManager + .getConnection(url, connectionProps)) { + boolean hasRdb = checkForRdbTables(conn); + boolean hasBeenConverted = checkForConversionTable(conn); + if (hasRdb && !hasBeenConverted) { + ss.fatal(this, String.format(MESSAGE_PROBLEM, url)); + ss.fatal(this, String.format(MESSAGE_TECHNICAL, url)); + ss.fatal(this, String.format(MESSAGE_WHAT_NOW, url)); + } + } catch (SQLException e) { + ss.fatal(this, "Can't connect to the database: " + PROPERTY_DB_URL + + "='" + url + "', " + PROPERTY_DB_USERNAME + "='" + + username + "'", e); + return; + } + } + + private boolean checkForRdbTables(Connection conn) throws SQLException { + DatabaseMetaData md = conn.getMetaData(); + try (ResultSet rs = md.getTables(null, null, TABLE_NAME_RDB, null);) { + while (rs.next()) { + return true; + } + } + return false; + } + + private boolean checkForConversionTable(Connection conn) + throws SQLException { + DatabaseMetaData md = conn.getMetaData(); + try (ResultSet rs = md.getTables(null, null, TABLE_NAME_CONVERSION, + null);) { + while (rs.next()) { + return true; + } + } + return false; + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + // Nothing to tear down. + } + +} diff --git a/webapp/web/WEB-INF/resources/startup_listeners.txt b/webapp/web/WEB-INF/resources/startup_listeners.txt index 8c18c5407..c33071954 100644 --- a/webapp/web/WEB-INF/resources/startup_listeners.txt +++ b/webapp/web/WEB-INF/resources/startup_listeners.txt @@ -11,6 +11,9 @@ edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesSetup edu.cornell.mannlib.vitro.webapp.config.ConfigurationPropertiesSmokeTests +# For the conversion from 1.6 or earlier (RDB) to 1.7 or later (TDB) +edu.cornell.mannlib.vitro.webapp.servlet.setup.GuardAgainstUnmigratedRDB + edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings$Setup edu.cornell.mannlib.vitro.webapp.application.ApplicationImpl$Setup