This commit is contained in:
millmanorama 2018-08-27 17:25:22 +02:00
parent 437f2446e8
commit d73f861d07
4 changed files with 142 additions and 123 deletions

View File

@ -69,7 +69,7 @@ public class NextUnseenGroup extends Action {
Optional.ofNullable(controller.viewState()) Optional.ofNullable(controller.viewState())
.map(ObjectExpression<GroupViewState>::getValue) .map(ObjectExpression<GroupViewState>::getValue)
.map(GroupViewState::getGroup) .map(GroupViewState::getGroup)
.ifPresent(group -> groupManager.markGroupSeen(group, true)); .ifPresent(group -> groupManager.saveGroupSeen(group, true));
if (unSeenGroups.isEmpty() == false) { if (unSeenGroups.isEmpty() == false) {
controller.advance(GroupViewState.tile(unSeenGroups.get(0)), true); controller.advance(GroupViewState.tile(unSeenGroups.get(0)), true);

View File

@ -80,7 +80,7 @@ import org.sqlite.SQLiteJDBCLoader;
*/ */
public final class DrawableDB { public final class DrawableDB {
private static final org.sleuthkit.autopsy.coreutils.Logger LOGGER = Logger.getLogger(DrawableDB.class.getName()); private static final org.sleuthkit.autopsy.coreutils.Logger logger = Logger.getLogger(DrawableDB.class.getName());
//column name constants////////////////////// //column name constants//////////////////////
private static final String ANALYZED = "analyzed"; //NON-NLS private static final String ANALYZED = "analyzed"; //NON-NLS
@ -147,7 +147,7 @@ public final class DrawableDB {
try { try {
Class.forName("org.sqlite.JDBC"); Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
LOGGER.log(Level.SEVERE, "Failed to load sqlite JDBC driver", ex); //NON-NLS logger.log(Level.SEVERE, "Failed to load sqlite JDBC driver", ex); //NON-NLS
} }
} }
private final SleuthkitCase tskCase; private final SleuthkitCase tskCase;
@ -259,7 +259,7 @@ public final class DrawableDB {
try { try {
caseDbTransaction.rollback(); caseDbTransaction.rollback();
} catch (TskCoreException ex2) { } catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2);
} }
} }
throw new ExceptionInInitializerError(ex); throw new ExceptionInInitializerError(ex);
@ -356,10 +356,10 @@ public final class DrawableDB {
try { try {
return new DrawableDB(dbPath.resolve("drawable.db"), controller); //NON-NLS return new DrawableDB(dbPath.resolve("drawable.db"), controller); //NON-NLS
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "sql error creating database connection", ex); //NON-NLS logger.log(Level.SEVERE, "sql error creating database connection", ex); //NON-NLS
return null; return null;
} catch (ExceptionInInitializerError | IOException ex) { } catch (ExceptionInInitializerError | IOException ex) {
LOGGER.log(Level.SEVERE, "error creating database connection", ex); //NON-NLS logger.log(Level.SEVERE, "error creating database connection", ex); //NON-NLS
return null; return null;
} }
} }
@ -391,11 +391,11 @@ public final class DrawableDB {
} }
try { try {
LOGGER.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS logger.log(Level.INFO, String.format("sqlite-jdbc version %s loaded in %s mode", //NON-NLS
SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode() SQLiteJDBCLoader.getVersion(), SQLiteJDBCLoader.isNativeMode()
? "native" : "pure-java")); //NON-NLS ? "native" : "pure-java")); //NON-NLS
} catch (Exception exception) { } catch (Exception exception) {
LOGGER.log(Level.WARNING, "exception while checking sqlite-jdbc version and mode", exception); //NON-NLS logger.log(Level.WARNING, "exception while checking sqlite-jdbc version and mode", exception); //NON-NLS
} }
} }
@ -414,7 +414,7 @@ public final class DrawableDB {
setPragmas(); setPragmas();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "problem accessing database", ex); //NON-NLS logger.log(Level.SEVERE, "problem accessing database", ex); //NON-NLS
return false; return false;
} }
@ -425,7 +425,7 @@ public final class DrawableDB {
+ " drawable_db_build_status VARCHAR(128) )"; //NON-NLS + " drawable_db_build_status VARCHAR(128) )"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "problem creating datasources table", ex); //NON-NLS logger.log(Level.SEVERE, "problem creating datasources table", ex); //NON-NLS
return false; return false;
} }
@ -442,7 +442,7 @@ public final class DrawableDB {
+ " analyzed integer DEFAULT 0)"; //NON-NLS + " analyzed integer DEFAULT 0)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "problem creating drawable_files table", ex); //NON-NLS logger.log(Level.SEVERE, "problem creating drawable_files table", ex); //NON-NLS
return false; return false;
} }
@ -459,7 +459,7 @@ public final class DrawableDB {
tskCase.getCaseDbAccessManager().createTable(GROUPS_TABLENAME, tableSchema); tskCase.getCaseDbAccessManager().createTable(GROUPS_TABLENAME, tableSchema);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "problem creating groups table", ex); //NON-NLS logger.log(Level.SEVERE, "problem creating groups table", ex); //NON-NLS
return false; return false;
} }
@ -469,7 +469,7 @@ public final class DrawableDB {
+ " hash_set_name VARCHAR(255) UNIQUE NOT NULL)"; //NON-NLS + " hash_set_name VARCHAR(255) UNIQUE NOT NULL)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "problem creating hash_sets table", ex); //NON-NLS logger.log(Level.SEVERE, "problem creating hash_sets table", ex); //NON-NLS
return false; return false;
} }
@ -480,7 +480,7 @@ public final class DrawableDB {
+ " PRIMARY KEY (hash_set_id, obj_id))"; //NON-NLS + " PRIMARY KEY (hash_set_id, obj_id))"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "problem creating hash_set_hits table", ex); //NON-NLS logger.log(Level.SEVERE, "problem creating hash_set_hits table", ex); //NON-NLS
return false; return false;
} }
@ -488,35 +488,35 @@ public final class DrawableDB {
String sql = "CREATE INDEX if not exists path_idx ON drawable_files(path)"; //NON-NLS String sql = "CREATE INDEX if not exists path_idx ON drawable_files(path)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem creating path_idx", ex); //NON-NLS logger.log(Level.WARNING, "problem creating path_idx", ex); //NON-NLS
} }
try (Statement stmt = con.createStatement()) { try (Statement stmt = con.createStatement()) {
String sql = "CREATE INDEX if not exists name_idx ON drawable_files(name)"; //NON-NLS String sql = "CREATE INDEX if not exists name_idx ON drawable_files(name)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem creating name_idx", ex); //NON-NLS logger.log(Level.WARNING, "problem creating name_idx", ex); //NON-NLS
} }
try (Statement stmt = con.createStatement()) { try (Statement stmt = con.createStatement()) {
String sql = "CREATE INDEX if not exists make_idx ON drawable_files(make)"; //NON-NLS String sql = "CREATE INDEX if not exists make_idx ON drawable_files(make)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem creating make_idx", ex); //NON-NLS logger.log(Level.WARNING, "problem creating make_idx", ex); //NON-NLS
} }
try (Statement stmt = con.createStatement()) { try (Statement stmt = con.createStatement()) {
String sql = "CREATE INDEX if not exists model_idx ON drawable_files(model)"; //NON-NLS String sql = "CREATE INDEX if not exists model_idx ON drawable_files(model)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem creating model_idx", ex); //NON-NLS logger.log(Level.WARNING, "problem creating model_idx", ex); //NON-NLS
} }
try (Statement stmt = con.createStatement()) { try (Statement stmt = con.createStatement()) {
String sql = "CREATE INDEX if not exists analyzed_idx ON drawable_files(analyzed)"; //NON-NLS String sql = "CREATE INDEX if not exists analyzed_idx ON drawable_files(analyzed)"; //NON-NLS
stmt.execute(sql); stmt.execute(sql);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem creating analyzed_idx", ex); //NON-NLS logger.log(Level.WARNING, "problem creating analyzed_idx", ex); //NON-NLS
} }
return true; return true;
@ -537,7 +537,7 @@ public final class DrawableDB {
closeStatements(); closeStatements();
con.close(); con.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Failed to close connection to drawable.db", ex); //NON-NLS logger.log(Level.WARNING, "Failed to close connection to drawable.db", ex); //NON-NLS
} }
} }
con = null; con = null;
@ -549,7 +549,7 @@ public final class DrawableDB {
con = DriverManager.getConnection("jdbc:sqlite:" + dbPath.toString()); //NON-NLS con = DriverManager.getConnection("jdbc:sqlite:" + dbPath.toString()); //NON-NLS
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Failed to open connection to drawable.db", ex); //NON-NLS logger.log(Level.WARNING, "Failed to open connection to drawable.db", ex); //NON-NLS
} }
} }
@ -600,7 +600,7 @@ public final class DrawableDB {
names.add(rs.getString(HASH_SET_NAME)); names.add(rs.getString(HASH_SET_NAME));
} }
} catch (SQLException sQLException) { } catch (SQLException sQLException) {
LOGGER.log(Level.WARNING, "failed to get hash set names", sQLException); //NON-NLS logger.log(Level.WARNING, "failed to get hash set names", sQLException); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -628,7 +628,7 @@ public final class DrawableDB {
} }
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "failed to get group seen", ex); //NON-NLS logger.log(Level.SEVERE, "failed to get group seen", ex); //NON-NLS
} }
} }
} }
@ -648,26 +648,22 @@ public final class DrawableDB {
return queryResultProcessor.getGroupSeen(); return queryResultProcessor.getGroupSeen();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
String msg = String.format("Failed to get is group seen for group key %s", groupKey.getValueDisplayName()); //NON-NLS String msg = String.format("Failed to get is group seen for group key %s", groupKey.getValueDisplayName()); //NON-NLS
LOGGER.log(Level.WARNING, msg, ex); logger.log(Level.WARNING, msg, ex);
} }
return false; return false;
} }
public void markGroupSeen(GroupKey<?> gk, boolean seen) { public void markGroupSeen(GroupKey<?> gk, boolean seen) throws TskCoreException {
try { String updateSQL;
String updateSQL; if (gk.getDataSource().isPresent()) {
if (gk.getDataSource().isPresent()) { updateSQL = String.format("SET seen = %d WHERE VALUE = \'%s\' AND attribute = \'%s\' AND data_source_obj_id = %d", seen ? 1 : 0,
updateSQL = String.format("SET seen = %d WHERE VALUE = \'%s\' AND attribute = \'%s\' AND data_source_obj_id = %d", seen ? 1 : 0, gk.getValueDisplayName(), gk.getAttribute().attrName.toString(), gk.getDataSourceObjId());
gk.getValueDisplayName(), gk.getAttribute().attrName.toString(), gk.getDataSourceObjId()); } else {
} else { updateSQL = String.format("SET seen = %d WHERE VALUE = \'%s\' AND attribute = \'%s\'", seen ? 1 : 0,
updateSQL = String.format("SET seen = %d WHERE VALUE = \'%s\' AND attribute = \'%s\'", seen ? 1 : 0, gk.getValueDisplayName(), gk.getAttribute().attrName.toString());
gk.getValueDisplayName(), gk.getAttribute().attrName.toString());
}
tskCase.getCaseDbAccessManager().update(GROUPS_TABLENAME, updateSQL);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error marking group as seen", ex); //NON-NLS
} }
tskCase.getCaseDbAccessManager().update(GROUPS_TABLENAME, updateSQL);
} }
public boolean removeFile(long id) { public boolean removeFile(long id) {
@ -695,10 +691,10 @@ public final class DrawableDB {
try { try {
caseDbTransaction.rollback(); caseDbTransaction.rollback();
} catch (TskCoreException ex2) { } catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
} }
} }
LOGGER.log(Level.SEVERE, "Error updating file", ex); //NON-NLS logger.log(Level.SEVERE, "Error updating file", ex); //NON-NLS
} }
} }
@ -720,10 +716,10 @@ public final class DrawableDB {
try { try {
caseDbTransaction.rollback(); caseDbTransaction.rollback();
} catch (TskCoreException ex2) { } catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS logger.log(Level.SEVERE, "Error in trying to rollback transaction", ex2); //NON-NLS
} }
} }
LOGGER.log(Level.SEVERE, "Error inserting file", ex); //NON-NLS logger.log(Level.SEVERE, "Error inserting file", ex); //NON-NLS
} }
} }
@ -792,7 +788,7 @@ public final class DrawableDB {
} }
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS logger.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS
} }
//and update all groups this file is in //and update all groups this file is in
@ -818,7 +814,7 @@ public final class DrawableDB {
* closed during processing, which doesn't need to be reported here. * closed during processing, which doesn't need to be reported here.
*/ */
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.SEVERE, "failed to insert/update file" + f.getContentPathSafe(), ex); //NON-NLS logger.log(Level.SEVERE, "failed to insert/update file" + f.getContentPathSafe(), ex); //NON-NLS
} }
} finally { } finally {
@ -850,14 +846,14 @@ public final class DrawableDB {
try { try {
rs.close(); rs.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing resultset", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing resultset", ex); //NON-NLS
} }
} }
if (statement != null) { if (statement != null) {
try { try {
statement.close(); statement.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing statement ", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing statement ", ex); //NON-NLS
} }
} }
dbReadUnlock(); dbReadUnlock();
@ -882,7 +878,7 @@ public final class DrawableDB {
updateDataSourceStmt.executeUpdate(); updateDataSourceStmt.executeUpdate();
} catch (SQLException | NullPointerException ex) { } catch (SQLException | NullPointerException ex) {
LOGGER.log(Level.SEVERE, "failed to insert/update datasources table", ex); //NON-NLS logger.log(Level.SEVERE, "failed to insert/update datasources table", ex); //NON-NLS
} finally { } finally {
dbWriteUnlock(); dbWriteUnlock();
} }
@ -919,7 +915,7 @@ public final class DrawableDB {
} }
} catch (SQLException ex) { } catch (SQLException ex) {
String msg = String.format("Failed to determine if file %s is finalized", String.valueOf(fileId)); //NON-NLS String msg = String.format("Failed to determine if file %s is finalized", String.valueOf(fileId)); //NON-NLS
LOGGER.log(Level.WARNING, msg, ex); logger.log(Level.WARNING, msg, ex);
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -937,7 +933,7 @@ public final class DrawableDB {
return analyzedQuery.getInt(ANALYZED) == fileIds.size(); return analyzedQuery.getInt(ANALYZED) == fileIds.size();
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem counting analyzed files: ", ex); //NON-NLS logger.log(Level.WARNING, "problem counting analyzed files: ", ex); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -964,10 +960,10 @@ public final class DrawableDB {
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem counting analyzed files: ", ex); //NON-NLS logger.log(Level.WARNING, "problem counting analyzed files: ", ex); //NON-NLS
} }
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
LOGGER.log(Level.WARNING, "problem counting analyzed files: ", tskCoreException); //NON-NLS logger.log(Level.WARNING, "problem counting analyzed files: ", tskCoreException); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -1004,14 +1000,14 @@ public final class DrawableDB {
try { try {
rs.close(); rs.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing result set after executing findAllFileIdsWhere", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing result set after executing findAllFileIdsWhere", ex); //NON-NLS
} }
} }
if (statement != null) { if (statement != null) {
try { try {
statement.close(); statement.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing statement after executing findAllFileIdsWhere", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing statement after executing findAllFileIdsWhere", ex); //NON-NLS
} }
} }
dbReadUnlock(); dbReadUnlock();
@ -1045,14 +1041,14 @@ public final class DrawableDB {
try { try {
rs.close(); rs.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing result set after executing countFilesWhere", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing result set after executing countFilesWhere", ex); //NON-NLS
} }
} }
if (statement != null) { if (statement != null) {
try { try {
statement.close(); statement.close();
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "Error closing statement after executing countFilesWhere", ex); //NON-NLS logger.log(Level.SEVERE, "Error closing statement after executing countFilesWhere", ex); //NON-NLS
} }
} }
dbReadUnlock(); dbReadUnlock();
@ -1132,7 +1128,7 @@ public final class DrawableDB {
vals.add(value); vals.add(value);
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "Unable to get values for attribute", ex); //NON-NLS logger.log(Level.WARNING, "Unable to get values for attribute", ex); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -1173,7 +1169,7 @@ public final class DrawableDB {
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
// Don't need to report it if the case was closed // Don't need to report it if the case was closed
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.SEVERE, "Unable to insert group", ex); //NON-NLS logger.log(Level.SEVERE, "Unable to insert group", ex); //NON-NLS
} }
} }
@ -1193,7 +1189,7 @@ public final class DrawableDB {
return DrawableFile.create(f, return DrawableFile.create(f,
areFilesAnalyzed(Collections.singleton(id)), isVideoFile(f)); areFilesAnalyzed(Collections.singleton(id)), isVideoFile(f));
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
LOGGER.log(Level.SEVERE, "there is no case open; failed to load file with id: {0}", id); //NON-NLS logger.log(Level.SEVERE, "there is no case open; failed to load file with id: {0}", id); //NON-NLS
return null; return null;
} }
} }
@ -1222,7 +1218,7 @@ public final class DrawableDB {
} }
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "failed to get file for group:" + groupKey.getAttribute() + " == " + groupKey.getValue(), ex); //NON-NLS logger.log(Level.WARNING, "failed to get file for group:" + groupKey.getAttribute() + " == " + groupKey.getValue(), ex); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -1282,7 +1278,7 @@ public final class DrawableDB {
//TODO: delete from hash_set_hits table also... //TODO: delete from hash_set_hits table also...
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "failed to delete row for obj_id = " + id, ex); //NON-NLS logger.log(Level.WARNING, "failed to delete row for obj_id = " + id, ex); //NON-NLS
} finally { } finally {
dbWriteUnlock(); dbWriteUnlock();
} }
@ -1343,7 +1339,7 @@ public final class DrawableDB {
addImageFileToList(analyzedQuery.getLong(OBJ_ID)); addImageFileToList(analyzedQuery.getLong(OBJ_ID));
} }
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.WARNING, "problem loading file IDs: ", ex); //NON-NLS logger.log(Level.WARNING, "problem loading file IDs: ", ex); //NON-NLS
} finally { } finally {
dbReadUnlock(); dbReadUnlock();
} }
@ -1394,9 +1390,9 @@ public final class DrawableDB {
.count(); .count();
} }
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
LOGGER.log(Level.WARNING, "Case closed while getting files"); //NON-NLS logger.log(Level.WARNING, "Case closed while getting files"); //NON-NLS
} catch (TskCoreException ex1) { } catch (TskCoreException ex1) {
LOGGER.log(Level.SEVERE, "Failed to get content tags by tag name.", ex1); //NON-NLS logger.log(Level.SEVERE, "Failed to get content tags by tag name.", ex1); //NON-NLS
} }
return -1; return -1;
@ -1445,7 +1441,7 @@ public final class DrawableDB {
return resultSet.getLong("obj_count"); //NON-NLS return resultSet.getLong("obj_count"); //NON-NLS
} }
} catch (SQLException | TskCoreException ex) { } catch (SQLException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting category count.", ex); //NON-NLS logger.log(Level.SEVERE, "Error getting category count.", ex); //NON-NLS
} }
return -1; return -1;
} }
@ -1479,7 +1475,7 @@ public final class DrawableDB {
con.setAutoCommit(false); con.setAutoCommit(false);
} catch (SQLException ex) { } catch (SQLException ex) {
LOGGER.log(Level.SEVERE, "failed to set auto-commit to to false", ex); //NON-NLS logger.log(Level.SEVERE, "failed to set auto-commit to to false", ex); //NON-NLS
} }
} }
@ -1490,7 +1486,7 @@ public final class DrawableDB {
con.rollback(); con.rollback();
updatedFiles.clear(); updatedFiles.clear();
} catch (SQLException ex1) { } catch (SQLException ex1) {
LOGGER.log(Level.SEVERE, "Exception while attempting to rollback!!", ex1); //NON-NLS logger.log(Level.SEVERE, "Exception while attempting to rollback!!", ex1); //NON-NLS
} finally { } finally {
close(); close();
} }
@ -1512,9 +1508,9 @@ public final class DrawableDB {
} }
} catch (SQLException ex) { } catch (SQLException ex) {
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.SEVERE, "Error commiting drawable.db.", ex); //NON-NLS logger.log(Level.SEVERE, "Error commiting drawable.db.", ex); //NON-NLS
} else { } else {
LOGGER.log(Level.WARNING, "Error commiting drawable.db - case is closed."); //NON-NLS logger.log(Level.WARNING, "Error commiting drawable.db - case is closed."); //NON-NLS
} }
rollback(); rollback();
} }
@ -1527,9 +1523,9 @@ public final class DrawableDB {
con.setAutoCommit(true); con.setAutoCommit(true);
} catch (SQLException ex) { } catch (SQLException ex) {
if (Case.isCaseOpen()) { if (Case.isCaseOpen()) {
LOGGER.log(Level.SEVERE, "Error setting auto-commit to true.", ex); //NON-NLS logger.log(Level.SEVERE, "Error setting auto-commit to true.", ex); //NON-NLS
} else { } else {
LOGGER.log(Level.SEVERE, "Error setting auto-commit to true - case is closed"); //NON-NLS logger.log(Level.SEVERE, "Error setting auto-commit to true - case is closed"); //NON-NLS
} }
} finally { } finally {
closed = true; closed = true;

View File

@ -174,6 +174,7 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
} }
} }
synchronized void addFile(Long f) { synchronized void addFile(Long f) {
if (fileIDs.contains(f) == false) { if (fileIDs.contains(f) == false) {
fileIDs.add(f); fileIDs.add(f);

View File

@ -19,6 +19,11 @@
package org.sleuthkit.autopsy.imagegallery.datamodel.grouping; package org.sleuthkit.autopsy.imagegallery.datamodel.grouping;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
@ -31,9 +36,12 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull; import static java.util.Objects.nonNull;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.logging.Level; import java.util.logging.Level;
@ -86,13 +94,17 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.DbType; import org.sleuthkit.datamodel.TskData.DbType;
/** /**
* Provides an abstraction layer on top of {@link DrawableDB} ( and to some * Provides an abstraction layer on top of DrawableDB ( and to some extent
* extent {@link SleuthkitCase} ) to facilitate creation, retrieval, updating, * SleuthkitCase ) to facilitate creation, retrieval, updating, and sorting of
* and sorting of {@link DrawableGroup}s. * DrawableGroups.
*/ */
public class GroupManager { public class GroupManager {
private static final Logger LOGGER = Logger.getLogger(GroupManager.class.getName()); private static final Logger logger = Logger.getLogger(GroupManager.class.getName());
/** An executor to submit async UI related background tasks to. */
private final ListeningExecutorService exec = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor(
new BasicThreadFactory.Builder().namingPattern("GUI Task -%d").build())); //NON-NLS
private final ImageGalleryController controller; private final ImageGalleryController controller;
@ -265,25 +277,40 @@ public class GroupManager {
} }
/** /**
* 'mark' the given group as seen. This removes it from the queue of groups * 'Save' the given group as seen in the drawable db.
* to review, and is persisted in the drawable db.
* *
* @param group The DrawableGroup to mark as seen. * @param group The DrawableGroup to mark as seen.
* @param seen The seen stastus to set. * @param seen The seen state to set for the given group.
*
* @return A ListenableFuture that encapsulates saving the seen state to the
* DB.
*/ */
@ThreadConfined(type = ThreadType.JFX) public ListenableFuture<?> saveGroupSeen(DrawableGroup group, boolean seen) {
public void markGroupSeen(DrawableGroup group, boolean seen) { synchronized (controller) {
DrawableDB db = getDB(); DrawableDB db = getDB();
if (nonNull(db)) { if (nonNull(db)) {
db.markGroupSeen(group.getGroupKey(), seen); return exec.submit(() -> {
group.setSeen(seen); try {
if (seen) { db.markGroupSeen(group.getGroupKey(), seen);
unSeenGroups.removeAll(group); group.setSeen(seen);
} else if (unSeenGroups.contains(group) == false) {
unSeenGroups.add(group); } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error marking group as seen", ex); //NON-NLS
}
});
} }
FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
} }
return Futures.immediateFuture(null);
}
@ThreadConfined(type = ThreadType.JFX)
private void updateUnSeenGroups(DrawableGroup group, boolean seen) {
if (seen) {
unSeenGroups.removeAll(group);
} else if (unSeenGroups.contains(group) == false) {
unSeenGroups.add(group);
}
FXCollections.sort(unSeenGroups, applySortOrder(sortOrder, sortBy));
} }
/** /**
@ -387,7 +414,7 @@ public class GroupManager {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "TSK error getting files in Category:" + category.getDisplayName(), ex); //NON-NLS logger.log(Level.WARNING, "TSK error getting files in Category:" + category.getDisplayName(), ex); //NON-NLS
throw ex; throw ex;
} }
} }
@ -406,7 +433,7 @@ public class GroupManager {
} }
return files; return files;
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "TSK error getting files with Tag:" + tagName.getDisplayName(), ex); //NON-NLS logger.log(Level.WARNING, "TSK error getting files with Tag:" + tagName.getDisplayName(), ex); //NON-NLS
throw ex; throw ex;
} }
} }
@ -495,7 +522,7 @@ public class GroupManager {
groupByTask = new ReGroupTask<>(dataSource, groupBy, sortBy, sortOrder); groupByTask = new ReGroupTask<>(dataSource, groupBy, sortBy, sortOrder);
Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty())); Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty()));
regroupExecutor.submit(groupByTask); exec.submit(groupByTask);
} else { } else {
// resort the list of groups // resort the list of groups
setSortBy(sortBy); setSortBy(sortBy);
@ -507,11 +534,6 @@ public class GroupManager {
} }
} }
/**
* an executor to submit async ui related background tasks to.
*/
final ExecutorService regroupExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder().namingPattern("ui task -%d").build()); //NON-NLS
public ReadOnlyDoubleProperty regroupProgress() { public ReadOnlyDoubleProperty regroupProgress() {
return regroupProgress.getReadOnlyProperty(); return regroupProgress.getReadOnlyProperty();
} }
@ -579,10 +601,9 @@ public class GroupManager {
} }
/** /**
* handle {@link FileUpdateEvent} sent from Db when files are * Handle notificationsS sent from Db when files are inserted/updated
* inserted/updated
* *
* @param evt * @param updatedFileIDs The ID of the inserted/updated files.
*/ */
@Subscribe @Subscribe
synchronized public void handleFileUpdate(Collection<Long> updatedFileIDs) { synchronized public void handleFileUpdate(Collection<Long> updatedFileIDs) {
@ -608,26 +629,22 @@ public class GroupManager {
} }
private DrawableGroup popuplateIfAnalyzed(GroupKey<?> groupKey, ReGroupTask<?> task) { private DrawableGroup popuplateIfAnalyzed(GroupKey<?> groupKey, ReGroupTask<?> task) {
/*
if (Objects.nonNull(task) && (task.isCancelled())) { * If this method call is part of a ReGroupTask and that task is
/* * cancelled, no-op.
* if this method call is part of a ReGroupTask and that task is *
* cancelled, no-op * This allows us to stop if a regroup task has been cancelled (e.g. the
* * user picked a different group by attribute, while the current task
* this allows us to stop if a regroup task has been cancelled (e.g. * was still running)
* the user picked a different group by attribute, while the current */
* task was still running) if (isNull(task) || task.isCancelled() == false) {
*/
} else { // no task or un-cancelled task
DrawableDB db = getDB(); DrawableDB db = getDB();
/*
* For attributes other than path we can't be sure a group is fully
* analyzed because we don't know all the files that will be a part
* of that group. just show them no matter what.
*/
if (nonNull(db) && ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey))) { if (nonNull(db) && ((groupKey.getAttribute() != DrawableAttribute.PATH) || db.isGroupAnalyzed(groupKey))) {
/*
* for attributes other than path we can't be sure a group is
* fully analyzed because we don't know all the files that will
* be a part of that group. just show them no matter what.
*/
try { try {
Set<Long> fileIDs = getFileIDsInGroup(groupKey); Set<Long> fileIDs = getFileIDsInGroup(groupKey);
if (Objects.nonNull(fileIDs)) { if (Objects.nonNull(fileIDs)) {
@ -636,34 +653,38 @@ public class GroupManager {
synchronized (groupMap) { synchronized (groupMap) {
if (groupMap.containsKey(groupKey)) { if (groupMap.containsKey(groupKey)) {
group = groupMap.get(groupKey); group = groupMap.get(groupKey);
group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet())); group.setFiles(ObjectUtils.defaultIfNull(fileIDs, Collections.emptySet()));
group.setSeen(groupSeen);
} else { } else {
group = new DrawableGroup(groupKey, fileIDs, groupSeen); group = new DrawableGroup(groupKey, fileIDs, groupSeen);
controller.getCategoryManager().registerListener(group); controller.getCategoryManager().registerListener(group);
group.seenProperty().addListener((o, oldSeen, newSeen) group.seenProperty().addListener((o, oldSeen, newSeen)
-> Platform.runLater(() -> markGroupSeen(group, newSeen)) -> saveGroupSeen(group, newSeen)
); .addListener(() -> updateUnSeenGroups(group, newSeen),
Platform::runLater));
groupMap.put(groupKey, group); groupMap.put(groupKey, group);
} }
} }
Platform.runLater(() -> { Platform.runLater(() -> {
if (analyzedGroups.contains(group) == false) { if (analyzedGroups.contains(group) == false) {
analyzedGroups.add(group); analyzedGroups.add(group);
if (Objects.isNull(task)) { if (isNull(task)) {
FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy)); FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy));
} }
} }
markGroupSeen(group, groupSeen); updateUnSeenGroups(group, groupSeen);
}); });
return group; return group;
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); //NON-NLS logger.log(Level.SEVERE, "failed to get files for group: " + groupKey.getAttribute().attrName.toString() + " = " + groupKey.getValue(), ex); //NON-NLS
} }
} }
} }
return null; return null;
} }
@ -687,6 +708,7 @@ public class GroupManager {
} catch (Exception ex) { } catch (Exception ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
throw new TskCoreException("Failed to get file ids with mime type " + mimeType, ex); throw new TskCoreException("Failed to get file ids with mime type " + mimeType, ex);
} }
} }
@ -842,7 +864,7 @@ public class GroupManager {
return values; return values;
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "TSK error getting list of type {0}", groupBy.getDisplayName()); //NON-NLS logger.log(Level.WARNING, "TSK error getting list of type {0}", groupBy.getDisplayName()); //NON-NLS
return Collections.emptyList(); return Collections.emptyList();
} }
} }