Merge pull request #3536 from rcordovano/merge-error-fix

Fix compile error, improve error handling in SQLiteViewer.java
This commit is contained in:
Richard Cordovano 2018-03-12 14:15:49 -04:00 committed by GitHub
commit 36d4414389
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -40,6 +40,7 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
@ -53,32 +54,27 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer; import org.sleuthkit.autopsy.corecomponentinterfaces.FileTypeViewer;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
/** /**
* A file content viewer for SQLITE db files. * A file content viewer for SQLite database files.
*
*/ */
public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final long serialVersionUID = 1L;
public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"}; public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"};
private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName());
private Connection connection = null;
private String tmpDBPathName = null;
private File tmpDBFile = null;
private final Map<String, String> dbTablesMap = new TreeMap<>();
private static final int ROWS_PER_PAGE = 100; private static final int ROWS_PER_PAGE = 100;
private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
private final SQLiteTableView selectedTableView = new SQLiteTableView();
private AbstractFile sqliteDbFile;
private File tmpDbFile;
private Connection connection;
private int numRows; // num of rows in the selected table private int numRows; // num of rows in the selected table
private int currPage = 0; // curr page of rows being displayed private int currPage = 0; // curr page of rows being displayed
SQLiteTableView selectedTableView = new SQLiteTableView();
private SwingWorker<? extends Object, ? extends Object> worker; private SwingWorker<? extends Object, ? extends Object> worker;
/** /**
* Creates new form SQLiteViewer * Constructs a file content viewer for SQLite database files.
*/ */
public SQLiteViewer() { public SQLiteViewer() {
initComponents(); initComponents();
@ -217,7 +213,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
currPage++; currPage++;
if (currPage * ROWS_PER_PAGE > numRows) { if (currPage * ROWS_PER_PAGE > numRows) {
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
@ -231,7 +226,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}//GEN-LAST:event_nextPageButtonActionPerformed }//GEN-LAST:event_nextPageButtonActionPerformed
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
currPage--; currPage--;
if (currPage == 1) { if (currPage == 1) {
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
@ -250,7 +244,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
if (null == tableName) { if (null == tableName) {
return; return;
} }
selectTable(tableName); selectTable(tableName);
}//GEN-LAST:event_tablesDropdownListActionPerformed }//GEN-LAST:event_tablesDropdownListActionPerformed
@ -276,7 +269,8 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override @Override
public void setFile(AbstractFile file) { public void setFile(AbstractFile file) {
processSQLiteFile(file); sqliteDbFile = file;
processSQLiteFile();
} }
@Override @Override
@ -286,9 +280,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
@Override @Override
public void resetComponent() { public void resetComponent() {
dbTablesMap.clear();
tablesDropdownList.setEnabled(true); tablesDropdownList.setEnabled(true);
tablesDropdownList.removeAllItems(); tablesDropdownList.removeAllItems();
numEntriesField.setText(""); numEntriesField.setText("");
@ -299,75 +290,61 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
connection.close(); connection.close();
connection = null; connection = null;
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS logger.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS
} }
} }
// delete last temp file // delete last temp file
if (null != tmpDBFile) { if (null != tmpDbFile) {
tmpDBFile.delete(); tmpDbFile.delete();
tmpDBFile = null; tmpDbFile = null;
} }
sqliteDbFile = null;
} }
/** /**
* Process the given SQLite DB file * Process the given SQLite DB file.
*
* @param sqliteFile -
*
* @return none
*/ */
@NbBundle.Messages({"# {0} - fileName", @NbBundle.Messages({
"SQLiteViewer.processSQLiteFile.errorMessage=Error opening SQLite file {0}" "SQLiteViewer.comboBox.noTableEntry=No tables found",
}) "SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.",
private void processSQLiteFile(AbstractFile sqliteFile) { "SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.",
"SQLiteViewer.errorMessage.failedToExtractFile=The file could not be extracted from the data source.",
tablesDropdownList.removeAllItems(); "SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.",
"SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
new SwingWorker<Void, Void>() { "# {0} - exception message", "SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
private void processSQLiteFile() {
SwingUtilities.invokeLater(() -> {
tablesDropdownList.removeAllItems();
});
new SwingWorker<Map<String, String>, Void>() {
@Override @Override
protected Void doInBackground() throws IOException, SQLException, ClassNotFoundException { protected Map<String, String> doInBackground() throws NoCurrentCaseException, TskCoreException, IOException, SQLException, ClassNotFoundException {
// Copy the file to temp folder
String tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteDbFile.getName();
tmpDbFile = new File(tmpDBPathName);
ContentUtils.writeToFile(sqliteDbFile, tmpDbFile);
try { // Look for any meta files associated with this DB - WAL, SHM, etc.
// Copy the file to temp folder findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-wal");
tmpDBPathName = Case.getOpenCase().getTempDirectory() + File.separator + sqliteFile.getName(); findAndCopySQLiteMetaFile(sqliteDbFile, sqliteDbFile.getName() + "-shm");
tmpDBFile = new File(tmpDBPathName);
ContentUtils.writeToFile(sqliteFile, tmpDBFile);
// look for any meta files associated with this DB - WAL, SHM // Load the SQLite JDBC driver, if necessary.
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal"); Class.forName("org.sqlite.JDBC"); //NON-NLS
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm"); connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
// Open copy using JDBC // Query the file for the table names and schemas.
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver return getTables();
connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS
// Read all table names and schema
return getTables();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Failed to copy DB file " + sqliteFile.getName(), ex); //NON-NLS
throw ex;
} catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Failed to get tables from DB file " + sqliteFile.getName(), ex); //NON-NLS
throw ex;
} catch (ClassNotFoundException ex) {
LOGGER.log(Level.SEVERE, "Failed to initialize JDBC SQLite.", ex); //NON-NLS
throw ex;
}
return null;
} }
@Override @Override
protected void done() { protected void done() {
super.done(); super.done();
try { try {
Map<String, String> dbTablesMap = get();
get();
if (dbTablesMap.isEmpty()) { if (dbTablesMap.isEmpty()) {
// Populate error message tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
tablesDropdownList.addItem("No tables found");
tablesDropdownList.setEnabled(false); tablesDropdownList.setEnabled(false);
} else { } else {
dbTablesMap.keySet().forEach((tableName) -> { dbTablesMap.keySet().forEach((tableName) -> {
@ -375,97 +352,76 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
}); });
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
logger.log(Level.SEVERE, String.format("Interrupted while opening SQLite database file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
LOGGER.log(Level.SEVERE, "Interrupted while opening DB file " + sqliteFile.getName(), ex); //NON-NLS MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_errorMessage_interrupted());
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), } catch (ExecutionException ex) {
ex.getMessage(), String errorMessage;
Bundle.SQLiteViewer_processSQLiteFile_errorMessage(sqliteFile.getName()), Throwable cause = ex.getCause();
JOptionPane.ERROR_MESSAGE); if (cause instanceof NoCurrentCaseException) {
} logger.log(Level.SEVERE, "Current case has been closed", ex); //NON-NLS
catch (ExecutionException ex) { errorMessage = Bundle.SQLiteViewer_errorMessage_noCurrentCase();
LOGGER.log(Level.SEVERE, "Unexpected exception while opening DB file " + sqliteFile.getName(), ex); //NON-NLS } else if (cause instanceof TskCoreException || cause instanceof IOException) {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), logger.log(Level.SEVERE, String.format("Failed to create temp copy of DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
ex.getCause().getMessage(), errorMessage = Bundle.SQLiteViewer_errorMessage_failedToExtractFile();
Bundle.SQLiteViewer_processSQLiteFile_errorMessage(sqliteFile.getName()), } else if (cause instanceof SQLException) {
JOptionPane.ERROR_MESSAGE); logger.log(Level.SEVERE, String.format("Failed to get tables from DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToQueryDatabase();
} else if (cause instanceof ClassNotFoundException) {
logger.log(Level.SEVERE, String.format("Failed to initialize JDBC SQLite '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
errorMessage = Bundle.SQLiteViewer_errorMessage_failedToinitJDBCDriver();
} else {
logger.log(Level.SEVERE, String.format("Unexpected exception while processing DB file '%s' (objId=%d)", sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
errorMessage = Bundle.SQLiteViewer_errorMessage_unexpectedError(cause.getLocalizedMessage());
}
MessageNotifyUtil.Message.error(errorMessage);
} }
} }
}.execute(); }.execute();
} }
/** /**
* Searches for a meta file associated with the give SQLite db * Searches for a meta file associated with the give SQLite db If found,
* If found, copies the file to the temp folder * copies the file to the temp folder
* *
* @param sqliteFile - SQLIte db file being processed * @param sqliteFile - SQLIte db file being processed
* @param metaFileName name of meta file to look for * @param metaFileName name of meta file to look for
*
* @return true if the meta file is found and copied successfully, false otherwise
*/ */
private boolean findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName ) { private void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
Case openCase; Case openCase = Case.getOpenCase();
try {
openCase = Case.getOpenCase();
} catch (NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
return false;
}
SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
Services services = new Services(sleuthkitCase); Services services = new Services(sleuthkitCase);
FileManager fileManager = services.getFileManager(); FileManager fileManager = services.getFileManager();
List<AbstractFile> metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName());
List<AbstractFile> metaFiles = null;
try {
metaFiles = fileManager.findFiles(sqliteFile.getDataSource(), metaFileName, sqliteFile.getParent().getName() );
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while searching SQLite meta file = " + metaFileName , ex); //NON-NLS
return false;
}
if (metaFiles != null) { if (metaFiles != null) {
for (AbstractFile metaFile: metaFiles) { for (AbstractFile metaFile : metaFiles) {
String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName(); String tmpMetafilePathName = openCase.getTempDirectory() + File.separator + metaFile.getName();
File tmpMetafile = new File(tmpMetafilePathName); File tmpMetafile = new File(tmpMetafilePathName);
try { ContentUtils.writeToFile(metaFile, tmpMetafile);
ContentUtils.writeToFile(metaFile, tmpMetafile);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Unexpected exception while copying SQLite meta file = " + metaFileName , ex); //NON-NLS
return false;
}
} }
} }
return true;
} }
/**
* Gets the table names and their schema from loaded SQLite db file
*
* @return true if success, false otherwise
*/
private void getTables() throws SQLException {
/**
* Gets the table names and schemas from the SQLite database file.
*
* @return A mapping of table names to SQL CREATE TABLE statements.
*/
private Map<String, String> getTables() throws SQLException {
Map<String, String> dbTablesMap = new TreeMap<>();
Statement statement = null; Statement statement = null;
ResultSet resultSet = null; ResultSet resultSet = null;
try { try {
statement = connection.createStatement(); statement = connection.createStatement();
resultSet = statement.executeQuery( resultSet = statement.executeQuery(
"SELECT name, sql FROM sqlite_master " "SELECT name, sql FROM sqlite_master "
+ " WHERE type= 'table' " + " WHERE type= 'table' "
+ " ORDER BY name;"); //NON-NLS + " ORDER BY name;"); //NON-NLS
while (resultSet.next()) { while (resultSet.next()) {
String tableName = resultSet.getString("name"); //NON-NLS String tableName = resultSet.getString("name"); //NON-NLS
String tableSQL = resultSet.getString("sql"); //NON-NLS String tableSQL = resultSet.getString("sql"); //NON-NLS
dbTablesMap.put(tableName, tableSQL); dbTablesMap.put(tableName, tableSQL);
} }
} catch(SQLException ex) { } finally {
throw ex;
}
finally {
if (null != resultSet) { if (null != resultSet) {
resultSet.close(); resultSet.close();
} }
@ -473,6 +429,7 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
statement.close(); statement.close();
} }
} }
return dbTablesMap;
} }
@NbBundle.Messages({"# {0} - tableName", @NbBundle.Messages({"# {0} - tableName",
@ -498,8 +455,7 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
return resultSet.getInt("count"); return resultSet.getInt("count");
} catch (SQLException ex) { } catch (SQLException ex) {
throw ex; throw ex;
} } finally {
finally {
if (null != resultSet) { if (null != resultSet) {
resultSet.close(); resultSet.close();
} }
@ -523,7 +479,6 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
if (numRows > 0) { if (numRows > 0) {
nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE))); nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE); readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
@ -532,19 +487,18 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
selectedTableView.setupTable(Collections.emptyList()); selectedTableView.setupTable(Collections.emptyList());
} }
} catch (InterruptedException ex ) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Interrupted while getting row count from table " + tableName, ex); //NON-NLS logger.log(Level.SEVERE, "Interrupted while getting row count from table " + tableName, ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getMessage(), ex.getMessage(),
Bundle.SQLiteViewer_selectTable_errorText(tableName), Bundle.SQLiteViewer_selectTable_errorText(tableName),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} } catch (ExecutionException ex) {
catch (ExecutionException ex) { logger.log(Level.SEVERE, "Unexpected exception while getting row count from table " + tableName, ex); //NON-NLS
LOGGER.log(Level.SEVERE, "Unexpected exception while getting row count from table " + tableName, ex); //NON-NLS JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), ex.getCause().getMessage(),
ex.getCause().getMessage(), Bundle.SQLiteViewer_selectTable_errorText(tableName),
Bundle.SQLiteViewer_selectTable_errorText(tableName), JOptionPane.ERROR_MESSAGE);
JOptionPane.ERROR_MESSAGE);
} }
} }
}; };
@ -563,7 +517,7 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
worker = new SwingWorker<ArrayList<Map<String, Object>>, Void>() { worker = new SwingWorker<ArrayList<Map<String, Object>>, Void>() {
@Override @Override
protected ArrayList<Map<String, Object>> doInBackground() throws Exception { protected ArrayList<Map<String, Object>> doInBackground() throws Exception {
Statement statement = null; Statement statement = null;
ResultSet resultSet = null; ResultSet resultSet = null;
try { try {
@ -573,12 +527,11 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
+ " LIMIT " + Integer.toString(numRowsToRead) + " LIMIT " + Integer.toString(numRowsToRead)
+ " OFFSET " + Integer.toString(startRow - 1) + " OFFSET " + Integer.toString(startRow - 1)
); //NON-NLS ); //NON-NLS
return resultSetToArrayList(resultSet); return resultSetToArrayList(resultSet);
} catch (SQLException ex) { } catch (SQLException ex) {
throw ex; throw ex;
} } finally {
finally {
if (null != resultSet) { if (null != resultSet) {
resultSet.close(); resultSet.close();
} }
@ -600,19 +553,18 @@ public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
ArrayList<Map<String, Object>> rows = get(); ArrayList<Map<String, Object>> rows = get();
if (Objects.nonNull(rows)) { if (Objects.nonNull(rows)) {
selectedTableView.setupTable(rows); selectedTableView.setupTable(rows);
}else{ } else {
selectedTableView.setupTable(Collections.emptyList()); selectedTableView.setupTable(Collections.emptyList());
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, "Interrupted while reading table " + tableName, ex); //NON-NLS logger.log(Level.SEVERE, "Interrupted while reading table " + tableName, ex); //NON-NLS
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getMessage(), ex.getMessage(),
Bundle.SQLiteViewer_readTable_errorText(tableName), Bundle.SQLiteViewer_readTable_errorText(tableName),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
} } catch (ExecutionException ex) {
catch (ExecutionException ex) { logger.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS
LOGGER.log(Level.SEVERE, "Unexpected exception while reading table " + tableName, ex); //NON-NLS JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
ex.getCause().getMessage(), ex.getCause().getMessage(),
Bundle.SQLiteViewer_readTable_errorText(tableName), Bundle.SQLiteViewer_readTable_errorText(tableName),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);