diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index ecec812771..4c7b66f27a 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -47,8 +47,26 @@ public interface EamDb { } } + /** + * Shutdown the connection pool. + * + * This closes the connection pool including all idle database connections. + * It will not close active/in-use connections. + * Thus, it is vital that there are no in-use connections + * when you call this method. + * + * @throws EamDbException if there is a problem closing the connection pool. + */ + void shutdownConnections() throws EamDbException; + /** * Update settings + * + * When using updateSettings, + * if any database settings have changed, you should call + * shutdownConnections() before using any API methods. + * That will ensure that any old connections are closed + * and all new connections will be made using the new settings. */ void updateSettings(); diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java index d4fdac0d14..85e976082f 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java @@ -50,7 +50,19 @@ public class PostgresEamDb extends AbstractSqlEamDb { private PostgresEamDb() { dbSettings = new PostgresEamDbSettings(); - updateSettings(); + bulkArtifactsThreshold = dbSettings.getBulkThreshold(); + } + + @Override + public void shutdownConnections() throws EamDbException { + try { + synchronized(this) { + connectionPool.close(); + connectionPool = null; // force it to be re-created on next connect() + } + } catch (SQLException ex) { + throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS + } } @Override diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index e4e4008068..51c11280a5 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -25,6 +25,7 @@ import java.sql.Statement; import java.util.List; import java.util.logging.Level; import org.apache.commons.dbcp2.BasicDataSource; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -50,9 +51,23 @@ public class SqliteEamDb extends AbstractSqlEamDb { private SqliteEamDb() { dbSettings = new SqliteEamDbSettings(); - updateSettings(); + bulkArtifactsThreshold = dbSettings.getBulkThreshold(); } + @Override + public void shutdownConnections() throws EamDbException { + try { + synchronized(this) { + if (null != connectionPool) { + connectionPool.close(); + connectionPool = null; // force it to be re-created on next connect() + } + } + } catch (SQLException ex) { + throw new EamDbException("Failed to close existing database connections.", ex); // NON-NLS + } + } + @Override public void updateSettings() { synchronized (this) { diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java index 1ac638c8ad..612f0d9937 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java @@ -18,7 +18,9 @@ import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; +import javax.swing.JOptionPane; import javax.swing.JTextField; +import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.netbeans.spi.options.OptionsPanelController; @@ -545,22 +547,58 @@ public class EamDbSettingsDialog extends JDialog { } }//GEN-LAST:event_bnCreateDbActionPerformed + @Messages({"EamDbSettingsDialog.okButton.errorTitle.text=Restart Required.", + "EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform."}) private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed + /** + * We have to shutdown the previous platform's connection pool first; + * assuming it wasn't DISABLED. This will close any existing idle + * connections. + * + * The next use of an EamDb API method will start a new connection pool + * using those new settings. + */ + try { + EamDb previousDbManager = EamDb.getInstance(); + if (null != previousDbManager) { + // NOTE: do not set/save the seleted platform before calling this. + EamDb.getInstance().shutdownConnections(); + } + } catch (EamDbException ex) { + LOGGER.log(Level.SEVERE, "Failed to close database connections in previously selected platform.", ex); // NON-NLS + SwingUtilities.invokeLater(() -> { + JOptionPane.showMessageDialog(null, + Bundle.EamDbSettingsDialog_okButton_errorMsg_text(), + Bundle.EamDbSettingsDialog_okButton_errorTitle_text(), + JOptionPane.WARNING_MESSAGE); + }); + } + + // Even if we fail to close the existing connections, make sure that we + // save the new connection settings, so an Autopsy restart will correctly + // start with the new settings. EamDbPlatformEnum.setSelectedPlatform(selectedPlatform.name()); EamDbPlatformEnum.saveSelectedPlatform(); + switch (selectedPlatform) { case POSTGRESQL: + // save the new PostgreSQL settings dbSettingsPostgres.saveSettings(); + // Load those newly saved settings into the postgres db manager instance + // in case we are still using the same instance. EamDb.getInstance().updateSettings(); break; case SQLITE: + // save the new SQLite settings dbSettingsSqlite.saveSettings(); + // Load those newly saved settings into the sqlite db manager instance + // in case we are still using the same instance. EamDb.getInstance().updateSettings(); break; case DISABLED: break; } - + dispose(); }//GEN-LAST:event_bnOkActionPerformed diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java index 6ed98be66f..0f1b976ff1 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ImportHashDatabaseDialog.java @@ -561,13 +561,11 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog { @NbBundle.Messages({"ImportHashDatabaseDialog.ImportHashDatabaseWorker.displayName=Importing Hash Database"}) private class ImportHashDatabaseWorker extends SwingWorker { - private final EamDb dbManager; private final File file; private final EamArtifactInstance.KnownStatus knownStatus; private final int globalSetID; public ImportHashDatabaseWorker(String filename, EamArtifactInstance.KnownStatus knownStatus, int globalSetID) throws EamDbException, UnknownHostException { - this.dbManager = EamDb.getInstance(); this.file = new File(filename); this.knownStatus = knownStatus; this.globalSetID = globalSetID; @@ -591,6 +589,7 @@ final class ImportHashDatabaseDialog extends javax.swing.JDialog { private void importHashDatabase(ProgressHandle progress) throws EamDbException, IOException { BufferedReader reader = new BufferedReader(new FileReader(file)); String line; + EamDb dbManager = EamDb.getInstance(); long totalLines = numberOfLinesInFile(file); if (totalLines <= Integer.MAX_VALUE) {