From 581955ea958086f554796c833e3f876b7473ae00 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 4 Apr 2018 12:38:20 -0400 Subject: [PATCH 01/64] Health monitor can create database --- .../CoordinationService.java | 3 +- .../org/sleuthkit/autopsy/core/Installer.java | 1 + .../healthmonitor/HealthMonitorException.java | 21 + .../autopsy/healthmonitor/Installer.java | 53 ++ .../healthmonitor/ServicesHealthMonitor.java | 508 ++++++++++++++++++ .../autopsy/healthmonitor/TimingMetric.java | 46 ++ 6 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java create mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java create mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java create mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java diff --git a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java index 9b2afff6b4..d7ef8c4750 100644 --- a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java +++ b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java @@ -457,7 +457,8 @@ public final class CoordinationService { CASES("cases"), MANIFESTS("manifests"), CONFIG("config"), - CENTRAL_REPO("centralRepository"); + CENTRAL_REPO("centralRepository"), + HEALTH_MONITOR("healthMonitor"); private final String displayName; diff --git a/Core/src/org/sleuthkit/autopsy/core/Installer.java b/Core/src/org/sleuthkit/autopsy/core/Installer.java index 83250f719d..63ac880171 100644 --- a/Core/src/org/sleuthkit/autopsy/core/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/core/Installer.java @@ -216,6 +216,7 @@ public class Installer extends ModuleInstall { packageInstallers.add(org.sleuthkit.autopsy.datamodel.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.ingest.Installer.getDefault()); packageInstallers.add(org.sleuthkit.autopsy.centralrepository.eventlisteners.Installer.getDefault()); + packageInstallers.add(org.sleuthkit.autopsy.healthmonitor.Installer.getDefault()); } /** diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java new file mode 100644 index 0000000000..26c39ef5b5 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java @@ -0,0 +1,21 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.healthmonitor; + +/** + * + */ +class HealthMonitorException extends Exception { + private static final long serialVersionUID = 1L; + + HealthMonitorException(String message) { + super(message); + } + + HealthMonitorException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java new file mode 100644 index 0000000000..537f3593ae --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java @@ -0,0 +1,53 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.healthmonitor; + +import java.util.logging.Level; +import org.openide.modules.ModuleInstall; +import org.sleuthkit.autopsy.coreutils.Logger; + +public class Installer extends ModuleInstall { + + private static final Logger logger = Logger.getLogger(Installer.class.getName()); + private static final long serialVersionUID = 1L; + + private static Installer instance; + + public synchronized static Installer getDefault() { + if (instance == null) { + instance = new Installer(); + } + return instance; + } + + private Installer() { + super(); + } + + @Override + public void restored() { + try { + ServicesHealthMonitor.startUp(); + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error starting health services monitor", ex); + } + } + + @Override + public boolean closing() { + //platform about to close + ServicesHealthMonitor.close(); + + return true; + } + + @Override + public void uninstalled() { + //module is being unloaded + ServicesHealthMonitor.close(); + + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java new file mode 100644 index 0000000000..67f096f77c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -0,0 +1,508 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.healthmonitor; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import org.apache.commons.dbcp2.BasicDataSource; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.core.UserPreferencesException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.datamodel.CaseDbConnectionInfo; +import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; + +/** + * + */ +public class ServicesHealthMonitor { + + private final static Logger logger = Logger.getLogger(ServicesHealthMonitor.class.getName()); + private final static String DATABASE_NAME = "ServicesHealthMonitor"; + private final static String MODULE_NAME = "ServicesHealthMonitor"; + private final static String IS_ENABLED_KEY = "is_enabled"; + private final static long DATABASE_WRITE_INTERVAL = 1; // Minutes + public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION + = new CaseDbSchemaVersionNumber(1, 0); + + private static final AtomicBoolean isEnabled = new AtomicBoolean(false); + private static ServicesHealthMonitor instance; + + private ScheduledThreadPoolExecutor periodicTasksExecutor; + private Map timingInfoMap; + private static final int CONN_POOL_SIZE = 5; + private BasicDataSource connectionPool = null; + + private ServicesHealthMonitor() throws HealthMonitorException { + System.out.println("\nCreating ServicesHealthMonitor"); + + // Create the map to collect timing metrics + timingInfoMap = new HashMap<>(); + + if (ModuleSettings.settingExists(MODULE_NAME, IS_ENABLED_KEY)) { + if(ModuleSettings.getConfigSetting(MODULE_NAME, IS_ENABLED_KEY).equals("true")){ + isEnabled.set(true); + activateMonitor(); + return; + } + } + isEnabled.set(false); + } + + private synchronized void activateMonitor() throws HealthMonitorException { + // Set up database (if needed) + System.out.println(" Setting up database..."); + if (!UserPreferences.getIsMultiUserModeEnabled()) { + throw new HealthMonitorException("Multi user mode is not enabled - can not activate services health monitor"); + } + + CoordinationService.Lock lock = getExclusiveDbLock(); + if(lock == null) { + throw new HealthMonitorException("Error getting database lock"); + } + + try { + // Check if the database exists + if (! databaseExists()) { + + // If not, create a new one + createDatabase(); + initializeDatabaseSchema(); + } + + // Any database upgrades would happen here + + } finally { + try { + lock.release(); + } catch (CoordinationService.CoordinationServiceException ex) { + throw new HealthMonitorException("Error releasing database lock", ex); + } + } + + // Prepare metric storage + System.out.println(" Clearing hash map..."); + timingInfoMap = new HashMap<>(); + + // Start the timer + System.out.println(" Starting the timer..."); + if(periodicTasksExecutor != null) { + // Make sure the previous executor (if it exists) has been stopped + periodicTasksExecutor.shutdown(); + } + periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build()); + periodicTasksExecutor.scheduleWithFixedDelay(new DatabaseWriteTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES); + + } + + private synchronized void deactivateMonitor() throws HealthMonitorException { + // Clear out the collected data + System.out.println(" Clearing hash map..."); + timingInfoMap.clear(); + + // Stop the timer + System.out.println(" Stopping the timer..."); + if(periodicTasksExecutor != null) { + periodicTasksExecutor.shutdown(); + } + + // Shut down the connection pool + shutdownConnections(); + } + + synchronized static ServicesHealthMonitor getInstance() throws HealthMonitorException { + if (instance == null) { + instance = new ServicesHealthMonitor(); + } + return instance; + } + + static synchronized void startUp() throws HealthMonitorException { + System.out.println("\nServicesHealthMonitor starting up"); + getInstance(); + } + + static synchronized void setEnabled(boolean enabled) throws HealthMonitorException { + System.out.println("\nServicesHealthMonitor setting enabled to " + enabled + "(previous: " + isEnabled.get() + ")"); + if(enabled == isEnabled.get()) { + // The setting has not changed, so do nothing + return; + } + + if(enabled) { + ModuleSettings.setConfigSetting(MODULE_NAME, IS_ENABLED_KEY, "true"); + isEnabled.set(true); + getInstance().activateMonitor(); + } else { + ModuleSettings.setConfigSetting(MODULE_NAME, IS_ENABLED_KEY, "false"); + isEnabled.set(false); + getInstance().deactivateMonitor(); + } + } + + public static TimingMetric getTimingMetric(String name) { + if(isEnabled.get()) { + return new TimingMetric(name); + } + return null; + } + + public static void submitTimingMetric(TimingMetric metric) { + if(isEnabled.get() && (metric != null)) { + metric.stopTiming(); + try { + getInstance().addTimingMetric(metric); + } catch (HealthMonitorException ex) { + // We don't want calling methods to have to check for exceptions, so just log it + logger.log(Level.SEVERE, "Error accessing services health monitor", ex); + } + } + } + + private void addTimingMetric(TimingMetric metric) { + try{ + synchronized(this) { + // There's a small check-then-act situation here where isEnabled + // may have changed before reaching this code, but it doesn't cause + // any errors to load a few extra entries into the map after disabling + // the monitor (they will be deleted if the monitor is re-enabled). + if(timingInfoMap.containsKey(metric.getName())) { + timingInfoMap.get(metric.getName()).addMetric(metric); + } else { + timingInfoMap.put(metric.getName(), new TimingInfo(metric)); + } + } + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error adding timing metric", ex); + } + } + + // Make private once testing is done + void writeCurrentStateToDatabase() { + System.out.println("\nwriteCurrentStateToDatabase"); + + Map timingMapCopy; + synchronized(this) { + if(! isEnabled.get()) { + return; + } + + // Make a shallow copy of the map. The map should be small - one entry + // per metric type. + timingMapCopy = new HashMap<>(timingInfoMap); + timingInfoMap.clear(); + } + + for(String name:timingMapCopy.keySet()){ + TimingInfo info = timingMapCopy.get(name); + long timestamp = System.currentTimeMillis(); + System.out.println(" Name: " + name + "\tTimestamp: " + timestamp + "\tAverage: " + info.getAverage() + + "\tMax: " + info.getMax() + "\tMin: " + info.getMin()); + } + } + + synchronized void clearCurrentState() { + timingInfoMap.clear(); + } + + static synchronized void close() { + if(isEnabled.get()) { + // Stop the timer + + // Write current data + try { + getInstance().writeCurrentStateToDatabase(); + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error writing final metric data to database", ex); + } + + // Shutdown connection pool + try { + getInstance().shutdownConnections(); + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error shutting down connection pool", ex); + } + + } + } + + synchronized void printCurrentState() { + System.out.println("\nTiming Info Map:"); + for(String name:timingInfoMap.keySet()) { + System.out.print(name + "\t"); + timingInfoMap.get(name).print(); + } + } + + // Change to private after testing + boolean databaseExists() throws HealthMonitorException { + + System.out.println("\nChecking database existence"); + + try { + // Use the same database settings as the case + CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); + Class.forName("org.postgresql.Driver"); //NON-NLS + ResultSet rs = null; + try (Connection connection = DriverManager.getConnection("jdbc:postgresql://" + db.getHost() + ":" + db.getPort() + "/postgres", db.getUserName(), db.getPassword()); //NON-NLS + Statement statement = connection.createStatement();) { + String createCommand = "SELECT 1 AS result FROM pg_database WHERE datname='" + DATABASE_NAME + "'"; + System.out.println(" query: " + createCommand); + rs = statement.executeQuery(createCommand); + if(rs.next()) { + System.out.println(" Exists!"); + return true; + } + } finally { + if(rs != null) { + rs.close(); + } + } + } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { + throw new HealthMonitorException("Failed check for health monitor database", ex); + } + System.out.println(" Does not exist"); + return false; + } + + private void createDatabase() throws HealthMonitorException { + try { + System.out.println("\nCreating database " + DATABASE_NAME); + // Use the same database settings as the case + CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); + Class.forName("org.postgresql.Driver"); //NON-NLS + try (Connection connection = DriverManager.getConnection("jdbc:postgresql://" + db.getHost() + ":" + db.getPort() + "/postgres", db.getUserName(), db.getPassword()); //NON-NLS + Statement statement = connection.createStatement();) { + String createCommand = "CREATE DATABASE \"" + DATABASE_NAME + "\" OWNER \"" + db.getUserName() + "\""; //NON-NLS + statement.execute(createCommand); + } + } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { + throw new HealthMonitorException("Failed to delete health monitor database", ex); + } + } + + + /** + * Delete the current health monitor database (for testing only) + * Make private after test + */ + void deleteDatabase() { + try { + // Use the same database settings as the case + CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); + Class.forName("org.postgresql.Driver"); //NON-NLS + try (Connection connection = DriverManager.getConnection("jdbc:postgresql://" + db.getHost() + ":" + db.getPort() + "/postgres", db.getUserName(), db.getPassword()); //NON-NLS + Statement statement = connection.createStatement();) { + String deleteCommand = "DROP DATABASE \"" + DATABASE_NAME + "\""; //NON-NLS + statement.execute(deleteCommand); + } + } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { + logger.log(Level.SEVERE, "Failed to delete health monitor database", ex); + } + } + + /** + * Setup a connection pool for db connections. + * + */ + private void setupConnectionPool() throws HealthMonitorException { + try { + CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); + + connectionPool = new BasicDataSource(); + //connectionPool.setUsername(db.getUserName()); + //connectionPool.setPassword(db.getPassword()); + connectionPool.setDriverClassName("org.postgresql.Driver"); + + StringBuilder connectionURL = new StringBuilder(); + connectionURL.append("jdbc:postgresql://"); + connectionURL.append(db.getHost()); + connectionURL.append(":"); + connectionURL.append(db.getPort()); + connectionURL.append("/"); + connectionURL.append(DATABASE_NAME); + + connectionPool.setUrl(connectionURL.toString()); + connectionPool.setUsername(db.getUserName()); + connectionPool.setPassword(db.getPassword()); + + // tweak pool configuration + connectionPool.setInitialSize(5); // start with 5 connections + connectionPool.setMaxIdle(CONN_POOL_SIZE); // max of 10 idle connections + connectionPool.setValidationQuery("SELECT version()"); + } catch (UserPreferencesException ex) { + throw new HealthMonitorException("Error loading database configuration", ex); + } + } + + public void shutdownConnections() throws HealthMonitorException { + try { + synchronized(this) { + if(connectionPool != null){ + connectionPool.close(); + connectionPool = null; // force it to be re-created on next connect() + } + } + } catch (SQLException ex) { + throw new HealthMonitorException("Failed to close existing database connections.", ex); // NON-NLS + } + } + + private Connection connect() throws HealthMonitorException { + synchronized (this) { + if (connectionPool == null) { + setupConnectionPool(); + } + } + + try { + return connectionPool.getConnection(); + } catch (SQLException ex) { + throw new HealthMonitorException("Error getting connection from connection pool.", ex); // NON-NLS + } + } + + private void initializeDatabaseSchema() throws HealthMonitorException { + Connection conn = connect(); + if(conn == null) { + throw new HealthMonitorException("Error getting database connection"); + } + + try (Statement statement = conn.createStatement()) { + StringBuilder createTimingTable = new StringBuilder(); + createTimingTable.append("CREATE TABLE IF NOT EXISTS timingData ("); + createTimingTable.append("id SERIAL PRIMARY KEY,"); + createTimingTable.append("name text NOT NULL,"); + createTimingTable.append("timestamp bigint NOT NULL,"); + createTimingTable.append("count bigint NOT NULL,"); + createTimingTable.append("average int NOT NULL,"); + createTimingTable.append("max int NOT NULL,"); + createTimingTable.append("min int NOT NULL"); + createTimingTable.append(")"); + statement.execute(createTimingTable.toString()); + + StringBuilder createDbInfoTable = new StringBuilder(); + createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info ("); + createDbInfoTable.append("id SERIAL PRIMARY KEY NOT NULL,"); + createDbInfoTable.append("name text NOT NULL,"); + createDbInfoTable.append("value text NOT NULL"); + createDbInfoTable.append(")"); + statement.execute(createDbInfoTable.toString()); + + statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); + statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); + + } catch (SQLException ex) { + throw new HealthMonitorException("Error initializing database", ex); + } finally { + try { + conn.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing Connection.", ex); + } + } + } + + private final class DatabaseWriteTask implements Runnable { + + /** + * Write current metric data to the database + */ + @Override + public void run() { + try { + System.out.println("\nTimer up - writing to DB"); + getInstance().writeCurrentStateToDatabase(); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Unexpected exception in DatabaseWriteTask", ex); //NON-NLS + } + } + } + + private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException{ + try { + String databaseNodeName = DATABASE_NAME; + CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.HEALTH_MONITOR, databaseNodeName, 5, TimeUnit.MINUTES); + + if(lock != null){ + return lock; + } + throw new HealthMonitorException("Error acquiring database lock"); + } catch (InterruptedException | CoordinationService.CoordinationServiceException ex){ + throw new HealthMonitorException("Error acquiring database lock"); + } + } + + private CoordinationService.Lock getSharedDbLock() throws HealthMonitorException{ + try { + String databaseNodeName = DATABASE_NAME; + CoordinationService.Lock lock = CoordinationService.getInstance().tryGetSharedLock(CoordinationService.CategoryNode.HEALTH_MONITOR, databaseNodeName, 5, TimeUnit.MINUTES); + + if(lock != null){ + return lock; + } + throw new HealthMonitorException("Error acquiring database lock"); + } catch (InterruptedException | CoordinationService.CoordinationServiceException ex){ + throw new HealthMonitorException("Error acquiring database lock"); + } + } + + private class TimingInfo { + private long count; + private long sum; + private long max; + private long min; + + TimingInfo(TimingMetric metric) throws HealthMonitorException { + count = 1; + sum = metric.getDuration(); + max = metric.getDuration(); + min = metric.getDuration(); + } + + void addMetric(TimingMetric metric) throws HealthMonitorException { + count++; + sum += metric.getDuration(); + + if(max < metric.getDuration()) { + max = metric.getDuration(); + } + + if(min > metric.getDuration()) { + min = metric.getDuration(); + } + } + + long getAverage() { + return sum / count; + } + + long getMax() { + return max; + } + + long getMin() { + return min; + } + + void print() { + System.out.println("count: " + count + "\tsum: " + sum + "\tmax: " + max + "\tmin: " + min); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java new file mode 100644 index 0000000000..431e585710 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.healthmonitor; + +/** + * + */ +public class TimingMetric { + + private final String name; + private final long startingTimestamp; + private Long duration; + + TimingMetric(String name) { + this.name = name; + this.startingTimestamp = System.nanoTime(); + this.duration = null; + } + + /** + * Record how long the metric was running. + */ + void stopTiming() { + long endingTimestamp = System.nanoTime(); + this.duration = endingTimestamp - startingTimestamp; + } + + /** + * Get the name of metric + * @return name + */ + String getName() { + return name; + } + + long getDuration() throws HealthMonitorException { + if (duration != null) { + return duration; + } else { + throw new HealthMonitorException("getDuration() called before stopTiming()"); + } + } +} From 94107ef1dca4e82f013b26a8af25252fdc2ef608 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 4 Apr 2018 14:33:16 -0400 Subject: [PATCH 02/64] Added metrics to Keyword Search --- Core/nbproject/project.xml | 1 + .../healthmonitor/ServicesHealthMonitor.java | 71 +++++++++++++++++-- .../autopsy/keywordsearch/Ingester.java | 4 ++ .../autopsy/keywordsearch/Server.java | 4 ++ 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 0159ec9880..5dabff9f5d 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -327,6 +327,7 @@ org.sleuthkit.autopsy.events org.sleuthkit.autopsy.filesearch org.sleuthkit.autopsy.guiutils + org.sleuthkit.autopsy.healthmonitor org.sleuthkit.autopsy.ingest org.sleuthkit.autopsy.keywordsearchservice org.sleuthkit.autopsy.menuactions diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index 67f096f77c..0bdf9d5e79 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -82,8 +82,11 @@ public class ServicesHealthMonitor { if (! databaseExists()) { // If not, create a new one + System.out.println(" No database exists - setting up new one"); createDatabase(); initializeDatabaseSchema(); + } else { + System.out.println(" Database already exists"); } // Any database upgrades would happen here @@ -194,7 +197,7 @@ public class ServicesHealthMonitor { } // Make private once testing is done - void writeCurrentStateToDatabase() { + void writeCurrentStateToDatabase() throws HealthMonitorException { System.out.println("\nwriteCurrentStateToDatabase"); Map timingMapCopy; @@ -208,13 +211,65 @@ public class ServicesHealthMonitor { timingMapCopy = new HashMap<>(timingInfoMap); timingInfoMap.clear(); } - + + // Check if there's anything to report + if(timingMapCopy.keySet().isEmpty()) { + System.out.println("No timing data to save"); + return; + } + + // Debug for(String name:timingMapCopy.keySet()){ TimingInfo info = timingMapCopy.get(name); long timestamp = System.currentTimeMillis(); System.out.println(" Name: " + name + "\tTimestamp: " + timestamp + "\tAverage: " + info.getAverage() + "\tMax: " + info.getMax() + "\tMin: " + info.getMin()); } + + CoordinationService.Lock lock = getSharedDbLock(); + if(lock == null) { + throw new HealthMonitorException("Error getting database lock"); + } + + try { + Connection conn = connect(); + if(conn == null) { + throw new HealthMonitorException("Error getting database connection"); + } + + //"INSERT INTO db_info (name, value) VALUES (?, ?)" + String addTimingInfoSql = "INSERT INTO timing_data (name, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?)"; + try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) { + + for(String name:timingMapCopy.keySet()) { + TimingInfo info = timingMapCopy.get(name); + + statement.setString(1, name); + statement.setLong(2, System.currentTimeMillis()); + statement.setLong(3, info.getCount()); + statement.setLong(4, info.getAverage()); + statement.setLong(5, info.getMax()); + statement.setLong(6, info.getMin()); + + statement.execute(); + } + + } catch (SQLException ex) { + throw new HealthMonitorException("Error saving metric data to database", ex); + } finally { + try { + conn.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing Connection.", ex); + } + } + } finally { + try { + lock.release(); + } catch (CoordinationService.CoordinationServiceException ex) { + throw new HealthMonitorException("Error releasing database lock", ex); + } + } } synchronized void clearCurrentState() { @@ -386,14 +441,14 @@ public class ServicesHealthMonitor { try (Statement statement = conn.createStatement()) { StringBuilder createTimingTable = new StringBuilder(); - createTimingTable.append("CREATE TABLE IF NOT EXISTS timingData ("); + createTimingTable.append("CREATE TABLE IF NOT EXISTS timing_data ("); createTimingTable.append("id SERIAL PRIMARY KEY,"); createTimingTable.append("name text NOT NULL,"); createTimingTable.append("timestamp bigint NOT NULL,"); createTimingTable.append("count bigint NOT NULL,"); - createTimingTable.append("average int NOT NULL,"); - createTimingTable.append("max int NOT NULL,"); - createTimingTable.append("min int NOT NULL"); + createTimingTable.append("average bigint NOT NULL,"); + createTimingTable.append("max bigint NOT NULL,"); + createTimingTable.append("min bigint NOT NULL"); createTimingTable.append(")"); statement.execute(createTimingTable.toString()); @@ -501,6 +556,10 @@ public class ServicesHealthMonitor { return min; } + long getCount() { + return count; + } + void print() { System.out.println("count: " + count + "\tsum: " + sum + "\tmax: " + max + "\tmin: " + min); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index c7f4c07f6a..679a646995 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -27,6 +27,8 @@ import org.apache.solr.common.SolrInputDocument; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.healthmonitor.ServicesHealthMonitor; +import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk; import org.sleuthkit.datamodel.AbstractFile; @@ -235,7 +237,9 @@ class Ingester { try { //TODO: consider timeout thread, or vary socket timeout based on size of indexed content + TimingMetric metric = ServicesHealthMonitor.getTimingMetric("solr index chunk"); solrServer.addDocument(updateDoc); + ServicesHealthMonitor.submitTimingMetric(metric); uncommitedIngests = true; } catch (KeywordSearchModuleException | NoOpenCoreException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 416f2b394f..3b4e494480 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -70,6 +70,8 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.healthmonitor.ServicesHealthMonitor; +import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException; import org.sleuthkit.datamodel.Content; @@ -773,7 +775,9 @@ public class Server { IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory()); currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS } + TimingMetric metric = ServicesHealthMonitor.getTimingMetric("solr connectivity check"); connectToSolrServer(currentSolrServer); + ServicesHealthMonitor.submitTimingMetric(metric); } catch (SolrServerException | IOException ex) { throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex); From f289685f254ddecadddb6a225cd877128ed8f346 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 5 Apr 2018 10:24:56 -0400 Subject: [PATCH 03/64] Cleanup and improved documentation --- .../healthmonitor/HealthMonitorException.java | 21 +- .../autopsy/healthmonitor/Installer.java | 19 +- .../healthmonitor/ServicesHealthMonitor.java | 334 +++++++++++++----- .../autopsy/healthmonitor/TimingMetric.java | 27 +- 4 files changed, 304 insertions(+), 97 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java index 26c39ef5b5..6df918acaa 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorException.java @@ -1,12 +1,25 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.healthmonitor; /** - * + * Exception used internally by the Services Health Monitor */ class HealthMonitorException extends Exception { private static final long serialVersionUID = 1L; diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java index 537f3593ae..b77ba067d7 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.healthmonitor; diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index 0bdf9d5e79..ab2510ca59 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.healthmonitor; @@ -19,7 +32,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import org.apache.commons.dbcp2.BasicDataSource; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferencesException; @@ -29,7 +41,11 @@ import org.sleuthkit.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; /** - * + * Class for recording data on the health of the system. + * + * For timing data: + * Modules will call getTimingMetric() before the code to be timed to get a TimingMetric object + * Modules will call submitTimingMetric() with the obtained TimingMetric object to log it */ public class ServicesHealthMonitor { @@ -45,16 +61,17 @@ public class ServicesHealthMonitor { private static ServicesHealthMonitor instance; private ScheduledThreadPoolExecutor periodicTasksExecutor; - private Map timingInfoMap; - private static final int CONN_POOL_SIZE = 5; + private final Map timingInfoMap; + private static final int CONN_POOL_SIZE = 10; private BasicDataSource connectionPool = null; private ServicesHealthMonitor() throws HealthMonitorException { - System.out.println("\nCreating ServicesHealthMonitor"); - // Create the map to collect timing metrics + // Create the map to collect timing metrics. The map will exist regardless + // of whether the monitor is enabled. timingInfoMap = new HashMap<>(); + // Read from module settings to determine if the module is enabled if (ModuleSettings.settingExists(MODULE_NAME, IS_ENABLED_KEY)) { if(ModuleSettings.getConfigSetting(MODULE_NAME, IS_ENABLED_KEY).equals("true")){ isEnabled.set(true); @@ -65,13 +82,32 @@ public class ServicesHealthMonitor { isEnabled.set(false); } + /** + * Get the instance of the ServicesHealthMonitor + * @return the instance + * @throws HealthMonitorException + */ + synchronized static ServicesHealthMonitor getInstance() throws HealthMonitorException { + if (instance == null) { + instance = new ServicesHealthMonitor(); + } + return instance; + } + + /** + * Activate the health monitor. + * Creates/initialized the database (if needed), clears any existing metrics + * out of the maps, and sets up the timer for writing to the database. + * @throws HealthMonitorException + */ private synchronized void activateMonitor() throws HealthMonitorException { - // Set up database (if needed) - System.out.println(" Setting up database..."); + + logger.log(Level.INFO, "Activating Servies Health Monitor"); + if (!UserPreferences.getIsMultiUserModeEnabled()) { throw new HealthMonitorException("Multi user mode is not enabled - can not activate services health monitor"); } - + // Set up database (if needed) CoordinationService.Lock lock = getExclusiveDbLock(); if(lock == null) { throw new HealthMonitorException("Error getting database lock"); @@ -85,8 +121,6 @@ public class ServicesHealthMonitor { System.out.println(" No database exists - setting up new one"); createDatabase(); initializeDatabaseSchema(); - } else { - System.out.println(" Database already exists"); } // Any database upgrades would happen here @@ -99,50 +133,69 @@ public class ServicesHealthMonitor { } } - // Prepare metric storage - System.out.println(" Clearing hash map..."); - timingInfoMap = new HashMap<>(); + // Clear out any old data + timingInfoMap.clear(); - // Start the timer - System.out.println(" Starting the timer..."); + // Start the timer for database writes + startTimer(); + } + + /** + * Deactivate the health monitor. + * This should only be used when disabling the monitor, not when Autopsy is closing. + * Clears out any metrics that haven't been written, stops the database write timer, + * and shuts down the connection pool. + * @throws HealthMonitorException + */ + private synchronized void deactivateMonitor() throws HealthMonitorException { + + logger.log(Level.INFO, "Deactivating Servies Health Monitor"); + + // Clear out the collected data + timingInfoMap.clear(); + + // Stop the timer + stopTimer(); + + // Shut down the connection pool + shutdownConnections(); + } + + /** + * Start the ScheduledThreadPoolExecutor that will handle the database writes. + */ + private synchronized void startTimer() { if(periodicTasksExecutor != null) { // Make sure the previous executor (if it exists) has been stopped periodicTasksExecutor.shutdown(); } periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build()); periodicTasksExecutor.scheduleWithFixedDelay(new DatabaseWriteTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES); - } - private synchronized void deactivateMonitor() throws HealthMonitorException { - // Clear out the collected data - System.out.println(" Clearing hash map..."); - timingInfoMap.clear(); - - // Stop the timer - System.out.println(" Stopping the timer..."); + /** + * Stop the ScheduledThreadPoolExecutor to prevent further database writes. + */ + private synchronized void stopTimer() { if(periodicTasksExecutor != null) { periodicTasksExecutor.shutdown(); } - - // Shut down the connection pool - shutdownConnections(); } - - synchronized static ServicesHealthMonitor getInstance() throws HealthMonitorException { - if (instance == null) { - instance = new ServicesHealthMonitor(); - } - return instance; - } - + + /** + * Called from the installer to set up the Health Monitor instance at startup. + * @throws HealthMonitorException + */ static synchronized void startUp() throws HealthMonitorException { - System.out.println("\nServicesHealthMonitor starting up"); getInstance(); } + /** + * Enabled/disable the health monitor. + * @param enabled true to enable the monitor, false to disable it + * @throws HealthMonitorException + */ static synchronized void setEnabled(boolean enabled) throws HealthMonitorException { - System.out.println("\nServicesHealthMonitor setting enabled to " + enabled + "(previous: " + isEnabled.get() + ")"); if(enabled == isEnabled.get()) { // The setting has not changed, so do nothing return; @@ -159,6 +212,16 @@ public class ServicesHealthMonitor { } } + /** + * Get a metric that will measure the time to execute a section of code. + * Call this before the section of code to be timed and then + * submit it afterward using submitTimingMetric(). + * This method is safe to call regardless of whether the Services Health + * Monitor is enabled. + * @param name A short but descriptive name describing the code being timed. + * This name will appear in the UI. + * @return The TimingMetric object + */ public static TimingMetric getTimingMetric(String name) { if(isEnabled.get()) { return new TimingMetric(name); @@ -166,6 +229,13 @@ public class ServicesHealthMonitor { return null; } + /** + * Submit the metric that was previously obtained through getTimingMetric(). + * Call this immediately after the section of code being timed. + * This method is safe to call regardless of whether the Services Health + * Monitor is enabled. + * @param metric The TimingMetric object obtained from getTimingMetric() + */ public static void submitTimingMetric(TimingMetric metric) { if(isEnabled.get() && (metric != null)) { metric.stopTiming(); @@ -173,52 +243,63 @@ public class ServicesHealthMonitor { getInstance().addTimingMetric(metric); } catch (HealthMonitorException ex) { // We don't want calling methods to have to check for exceptions, so just log it - logger.log(Level.SEVERE, "Error accessing services health monitor", ex); + logger.log(Level.SEVERE, "Error adding timing metric", ex); } } } - private void addTimingMetric(TimingMetric metric) { - try{ - synchronized(this) { - // There's a small check-then-act situation here where isEnabled - // may have changed before reaching this code, but it doesn't cause - // any errors to load a few extra entries into the map after disabling - // the monitor (they will be deleted if the monitor is re-enabled). - if(timingInfoMap.containsKey(metric.getName())) { - timingInfoMap.get(metric.getName()).addMetric(metric); - } else { - timingInfoMap.put(metric.getName(), new TimingInfo(metric)); - } + /** + * Add the timing metric data to the map. + * @param metric The metric to add. stopTiming() should already have been called. + */ + private void addTimingMetric(TimingMetric metric) throws HealthMonitorException { + + // Do as little as possible within the synchronized block to minimize + // blocking with multiple threads. + synchronized(this) { + // There's a small check-then-act situation here where isEnabled + // may have changed before reaching this code. This is fine - + // the map still exists and any extra data added after the monitor + // is disabled will be deleted if the monitor is re-enabled. This + // seems preferable to doing another check on isEnabled within + // the synchronized block. + if(timingInfoMap.containsKey(metric.getName())) { + timingInfoMap.get(metric.getName()).addMetric(metric); + } else { + timingInfoMap.put(metric.getName(), new TimingInfo(metric)); } - } catch (HealthMonitorException ex) { - logger.log(Level.SEVERE, "Error adding timing metric", ex); } } - // Make private once testing is done + // TODO: Make private once testing is done + /** + * Write the collected metrics to the database. + * @throws HealthMonitorException + */ void writeCurrentStateToDatabase() throws HealthMonitorException { - System.out.println("\nwriteCurrentStateToDatabase"); + logger.log(Level.INFO, "Writing health monitor metrics to database"); Map timingMapCopy; + + // Do as little as possible within the synchronized block since it will + // block threads attempting to record metrics. synchronized(this) { if(! isEnabled.get()) { return; } - // Make a shallow copy of the map. The map should be small - one entry - // per metric type. + // Make a shallow copy of the timing map. The map should be small - one entry + // per metric name. timingMapCopy = new HashMap<>(timingInfoMap); timingInfoMap.clear(); } - // Check if there's anything to report + // Check if there's anything to report (right now we only have the timing map) if(timingMapCopy.keySet().isEmpty()) { - System.out.println("No timing data to save"); return; } - // Debug + // TODO: Debug for(String name:timingMapCopy.keySet()){ TimingInfo info = timingMapCopy.get(name); long timestamp = System.currentTimeMillis(); @@ -226,6 +307,7 @@ public class ServicesHealthMonitor { "\tMax: " + info.getMax() + "\tMin: " + info.getMin()); } + // Write to the database CoordinationService.Lock lock = getSharedDbLock(); if(lock == null) { throw new HealthMonitorException("Error getting database lock"); @@ -237,7 +319,7 @@ public class ServicesHealthMonitor { throw new HealthMonitorException("Error getting database connection"); } - //"INSERT INTO db_info (name, value) VALUES (?, ?)" + // Add timing metrics to the database String addTimingInfoSql = "INSERT INTO timing_data (name, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?)"; try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) { @@ -272,13 +354,23 @@ public class ServicesHealthMonitor { } } + // TODO: debug synchronized void clearCurrentState() { timingInfoMap.clear(); } + /** + * Call during application closing - attempts to log any remaining entries. + */ static synchronized void close() { if(isEnabled.get()) { + // Stop the timer + try { + getInstance().stopTimer(); + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error shutting down timer", ex); + } // Write current data try { @@ -293,10 +385,10 @@ public class ServicesHealthMonitor { } catch (HealthMonitorException ex) { logger.log(Level.SEVERE, "Error shutting down connection pool", ex); } - } } + // TODO: debug synchronized void printCurrentState() { System.out.println("\nTiming Info Map:"); for(String name:timingInfoMap.keySet()) { @@ -305,11 +397,14 @@ public class ServicesHealthMonitor { } } - // Change to private after testing - boolean databaseExists() throws HealthMonitorException { - - System.out.println("\nChecking database existence"); - + // TODO: Change to private after testing + /** + * Check whether the health monitor database exists. + * Does not check the schema. + * @return true if the database exists, false otherwise + * @throws HealthMonitorException + */ + boolean databaseExists() throws HealthMonitorException { try { // Use the same database settings as the case CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); @@ -321,7 +416,7 @@ public class ServicesHealthMonitor { System.out.println(" query: " + createCommand); rs = statement.executeQuery(createCommand); if(rs.next()) { - System.out.println(" Exists!"); + logger.log(Level.INFO, "Existing Services Health Monitor database found"); return true; } } finally { @@ -332,13 +427,15 @@ public class ServicesHealthMonitor { } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { throw new HealthMonitorException("Failed check for health monitor database", ex); } - System.out.println(" Does not exist"); return false; } + /** + * Create a new health monitor database. + * @throws HealthMonitorException + */ private void createDatabase() throws HealthMonitorException { try { - System.out.println("\nCreating database " + DATABASE_NAME); // Use the same database settings as the case CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); Class.forName("org.postgresql.Driver"); //NON-NLS @@ -347,12 +444,13 @@ public class ServicesHealthMonitor { String createCommand = "CREATE DATABASE \"" + DATABASE_NAME + "\" OWNER \"" + db.getUserName() + "\""; //NON-NLS statement.execute(createCommand); } + logger.log(Level.INFO, "Created new health monitor database " + DATABASE_NAME); } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { throw new HealthMonitorException("Failed to delete health monitor database", ex); } } - + // TODO: At least make private /** * Delete the current health monitor database (for testing only) * Make private after test @@ -371,18 +469,16 @@ public class ServicesHealthMonitor { logger.log(Level.SEVERE, "Failed to delete health monitor database", ex); } } - + /** * Setup a connection pool for db connections. - * + * @throws HealthMonitorException */ private void setupConnectionPool() throws HealthMonitorException { try { CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); connectionPool = new BasicDataSource(); - //connectionPool.setUsername(db.getUserName()); - //connectionPool.setPassword(db.getPassword()); connectionPool.setDriverClassName("org.postgresql.Driver"); StringBuilder connectionURL = new StringBuilder(); @@ -398,7 +494,7 @@ public class ServicesHealthMonitor { connectionPool.setPassword(db.getPassword()); // tweak pool configuration - connectionPool.setInitialSize(5); // start with 5 connections + connectionPool.setInitialSize(2); // start with 2 connections connectionPool.setMaxIdle(CONN_POOL_SIZE); // max of 10 idle connections connectionPool.setValidationQuery("SELECT version()"); } catch (UserPreferencesException ex) { @@ -406,7 +502,11 @@ public class ServicesHealthMonitor { } } - public void shutdownConnections() throws HealthMonitorException { + /** + * Shut down the connection pool + * @throws HealthMonitorException + */ + private void shutdownConnections() throws HealthMonitorException { try { synchronized(this) { if(connectionPool != null){ @@ -419,6 +519,12 @@ public class ServicesHealthMonitor { } } + /** + * Get a database connection. + * Sets up the connection pool if needed. + * @return The Connection object + * @throws HealthMonitorException + */ private Connection connect() throws HealthMonitorException { synchronized (this) { if (connectionPool == null) { @@ -433,12 +539,17 @@ public class ServicesHealthMonitor { } } + /** + * Initialize the database. + * @throws HealthMonitorException + */ private void initializeDatabaseSchema() throws HealthMonitorException { Connection conn = connect(); if(conn == null) { throw new HealthMonitorException("Error getting database connection"); } + // TODO: transaction try (Statement statement = conn.createStatement()) { StringBuilder createTimingTable = new StringBuilder(); createTimingTable.append("CREATE TABLE IF NOT EXISTS timing_data ("); @@ -474,6 +585,10 @@ public class ServicesHealthMonitor { } } + /** + * The task called by the ScheduledThreadPoolExecutor to handle + * the database writes. + */ private final class DatabaseWriteTask implements Runnable { /** @@ -482,14 +597,19 @@ public class ServicesHealthMonitor { @Override public void run() { try { - System.out.println("\nTimer up - writing to DB"); getInstance().writeCurrentStateToDatabase(); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Unexpected exception in DatabaseWriteTask", ex); //NON-NLS + } catch (HealthMonitorException ex) { + logger.log(Level.SEVERE, "Error writing current metrics to database", ex); //NON-NLS } } } + /** + * Get an exclusive lock for the health monitor database. + * Acquire this before creating, initializing, or updating the database schema. + * @return The lock + * @throws HealthMonitorException + */ private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException{ try { String databaseNodeName = DATABASE_NAME; @@ -504,6 +624,12 @@ public class ServicesHealthMonitor { } } + /** + * Get an shared lock for the health monitor database. + * Acquire this before database reads or writes. + * @return The lock + * @throws HealthMonitorException + */ private CoordinationService.Lock getSharedDbLock() throws HealthMonitorException{ try { String databaseNodeName = DATABASE_NAME; @@ -518,11 +644,19 @@ public class ServicesHealthMonitor { } } + /** + * Internal class for collecting timing metrics. + * Instead of storing each TimingMetric, we only store the min and max + * seen and the number of metrics and total duration to compute the average + * later. + * One TimingInfo instance should be created per metric name, and + * additional timing metrics will be added to it. + */ private class TimingInfo { - private long count; - private long sum; - private long max; - private long min; + private long count; // Number of metrics collected + private long sum; // Sum of the durations collected (nanoseconds) + private long max; // Maximum value found (nanoseconds) + private long min; // Minimum value found (nanoseconds) TimingInfo(TimingMetric metric) throws HealthMonitorException { count = 1; @@ -531,35 +665,63 @@ public class ServicesHealthMonitor { min = metric.getDuration(); } + /** + * Add a new TimingMetric to an existing TimingInfo object. + * This is called in a synchronized block for almost all new + * TimingMetric objects, so do as little processing here as possible. + * @param metric The new metric + * @throws HealthMonitorException Will be thrown if the metric hasn't been stopped + */ void addMetric(TimingMetric metric) throws HealthMonitorException { + + // Keep track of needed info to calculate the average count++; sum += metric.getDuration(); + // Check if this is the longest duration seen if(max < metric.getDuration()) { max = metric.getDuration(); } + // Check if this is the lowest duration seen if(min > metric.getDuration()) { min = metric.getDuration(); } } + /** + * Get the average duration + * @return average duration (nanoseconds) + */ long getAverage() { return sum / count; } + /** + * Get the maximum duration + * @return maximum duration (nanoseconds) + */ long getMax() { return max; } + /** + * Get the minimum duration + * @return minimum duration (nanoseconds) + */ long getMin() { return min; } + /** + * Get the total number of metrics collected + * @return number of metrics collected + */ long getCount() { return count; } + // TODO: debug void print() { System.out.println("count: " + count + "\tsum: " + sum + "\tmax: " + max + "\tmin: " + min); } diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java index 431e585710..d94dfd7161 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/TimingMetric.java @@ -1,12 +1,25 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.healthmonitor; /** - * + * Used to calculate and report timing metrics. */ public class TimingMetric { @@ -36,6 +49,12 @@ public class TimingMetric { return name; } + /** + * Get the duration of the metric. Will throw an exception if the + * metric has not been stopped. + * @return how long the metric was running (nanoseconds) + * @throws HealthMonitorException + */ long getDuration() throws HealthMonitorException { if (duration != null) { return duration; From 7176c6edf1ee844681687048e0d52afcd4ca228c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 5 Apr 2018 12:05:11 -0400 Subject: [PATCH 04/64] 3610 initial swapping of jtables for outlineviews on AutoIngestDashboard --- Experimental/nbproject/project.xml | 16 + .../autoingest/AutoIngestDashboard.form | 58 +- .../autoingest/AutoIngestDashboard.java | 862 +++++++++--------- .../autoingest/AutoIngestJobsPanel.form | 18 + .../autoingest/AutoIngestJobsPanel.java | 173 ++++ .../autoingest/AutoIngestNode.java | 134 +++ .../experimental/autoingest/Bundle.properties | 3 - 7 files changed, 767 insertions(+), 497 deletions(-) create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.form create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index dbd5a31c4c..54e7d881b2 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -33,6 +33,14 @@ 1.49.1 + + org.netbeans.swing.outline + + + + 1.34.1 + + org.openide.awt @@ -49,6 +57,14 @@ 7.41.1 + + org.openide.explorer + + + + 6.62.1 + + org.openide.filesystems diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 9d2a343f56..68a1bb656d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -73,7 +73,7 @@ - + @@ -98,27 +98,19 @@ + + + + + + + + - - - - - - - - - - - - - - - - @@ -126,22 +118,6 @@ - - - - - - - - - - - - - - - - @@ -149,22 +125,6 @@ - - - - - - - - - - - - - - - - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 3389a64a03..fb5abdc686 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -35,18 +35,25 @@ import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; import javax.swing.JPanel; import javax.swing.JTable; +import javax.swing.ListSelectionModel; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.table.DefaultTableModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; import javax.swing.table.TableColumn; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; @@ -82,11 +89,14 @@ final class AutoIngestDashboard extends JPanel implements Observer { private static final int COMPLETED_TIME_COL_MAX_WIDTH = 2000; private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280; private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboard.class.getName()); - private final DefaultTableModel pendingTableModel; - private final DefaultTableModel runningTableModel; - private final DefaultTableModel completedTableModel; + // private final DefaultTableModel pendingTableModel; +// private final DefaultTableModel runningTableModel; +// private final DefaultTableModel completedTableModel; private AutoIngestMonitor autoIngestMonitor; - + private AutoIngestJobsPanel pendingJobsPanel; + private AutoIngestJobsPanel runningJobsPanel; + private AutoIngestJobsPanel finishedJobsPanel; + /** * Maintain a mapping of each service to it's last status update. */ @@ -115,36 +125,53 @@ final class AutoIngestDashboard extends JPanel implements Observer { */ private AutoIngestDashboard() { this.statusByService = new ConcurrentHashMap<>(); - - pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - - runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); - - completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); +// pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); +// runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); +// completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); initComponents(); statusByService.put(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.MESSAGING.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); setServicesStatusMessage(); - initPendingJobsTable(); - initRunningJobsTable(); - initCompletedJobsTable(); - + // initPendingJobsTable(); +// initRunningJobsTable(); +// initCompletedJobsTable(); + pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.PENDING_JOB); + pendingJobsPanel.setSize(pendingScrollPane.getSize()); + pendingScrollPane.add(pendingJobsPanel); + pendingScrollPane.setViewportView(pendingJobsPanel); + pendingJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { + System.out.println("SELECTION HAPPENED PENDING WJS-TODO"); + }); + runningJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.RUNNING_JOB); + runningJobsPanel.setSize(runningScrollPane.getSize()); + runningScrollPane.add(runningJobsPanel); + runningScrollPane.setViewportView(runningJobsPanel); + runningJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { + System.out.println("SELECTION HAPPENED RUNNING WJS-TODO"); + }); + finishedJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.COMPLETED_JOB); + finishedJobsPanel.setSize(completedScrollPane.getSize()); + completedScrollPane.add(finishedJobsPanel); + completedScrollPane.setViewportView(finishedJobsPanel); + finishedJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { + System.out.println("SELECTION HAPPENED COMPLETED WJS-TODO"); + }); /* * Must set this flag, otherwise pop up menus don't close properly. */ UIManager.put("PopupMenu.consumeEventOnClose", false); } - + /** * Update status of the services on the dashboard */ private void displayServicesStatus() { - tbServicesStatusMessage.setText(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message", - statusByService.get(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()), - statusByService.get(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()), - statusByService.get(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()), + tbServicesStatusMessage.setText(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message", + statusByService.get(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()), + statusByService.get(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()), + statusByService.get(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()), statusByService.get(ServicesMonitor.Service.MESSAGING.toString()))); String upStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up"); if (statusByService.get(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()).compareTo(upStatus) != 0 @@ -162,7 +189,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { */ private void setServicesStatusMessage() { new SwingWorker() { - + @Override protected Void doInBackground() throws Exception { statusByService.put(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString(), getServiceStatus(ServicesMonitor.Service.REMOTE_CASE_DATABASE)); @@ -202,233 +229,231 @@ final class AutoIngestDashboard extends JPanel implements Observer { }.execute(); } - /** - * Sets up the JTable that presents a view of the pending jobs queue for an - * auto ingest cluster. - */ - private void initPendingJobsTable() { - /* - * Remove some of the jobs table model columns from the JTable. This - * does not remove the columns from the model, just from this table. - */ - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - - /* - * Set up a column to display the cases associated with the jobs. - */ - TableColumn column; - column = pendingTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); - column.setMinWidth(GENERIC_COL_MIN_WIDTH); - column.setMaxWidth(GENERIC_COL_MAX_WIDTH); - column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); - column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the data sources associated with the jobs. - */ - column = pendingTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); - column.setMaxWidth(GENERIC_COL_MAX_WIDTH); - column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); - column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the create times of the jobs. - */ - column = pendingTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); - column.setCellRenderer(new LongDateCellRenderer()); - column.setMinWidth(TIME_COL_MIN_WIDTH); - column.setMaxWidth(TIME_COL_MAX_WIDTH); - column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - column.setWidth(TIME_COL_PREFERRED_WIDTH); - - column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); - column.setCellRenderer(new PrioritizedIconCellRenderer()); - column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); - column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); - column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); - /* - * Allow sorting when a column header is clicked. - */ - pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); - - /* - * Create a row selection listener to enable/disable the Prioritize - * button. - */ - pendingTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { - if (e.getValueIsAdjusting()) { - return; - } - int row = pendingTable.getSelectedRow(); - - boolean enablePrioritizeButtons = false; - boolean enableDeprioritizeButtons = false; - if (row >= 0 && row < pendingTable.getRowCount()) { - enablePrioritizeButtons = true; - enableDeprioritizeButtons = (Integer) pendingTableModel.getValueAt(row, JobsTableModelColumns.PRIORITY.ordinal()) > 0; - } - this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); - this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); - this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); - this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); - }); - } - - /** - * Sets up the JTable that presents a view of the running jobs list for an - * auto ingest cluster. - */ - private void initRunningJobsTable() { - /* - * Remove some of the jobs table model columns from the JTable. This - * does not remove the columns from the model, just from this table. - */ - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); - /* - * Set up a column to display the cases associated with the jobs. - */ - TableColumn column; - column = runningTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); - column.setMinWidth(GENERIC_COL_MIN_WIDTH); - column.setMaxWidth(GENERIC_COL_MAX_WIDTH); - column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); - column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the image folders associated with the - * jobs. - */ - column = runningTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); - column.setMinWidth(GENERIC_COL_MIN_WIDTH); - column.setMaxWidth(GENERIC_COL_MAX_WIDTH); - column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); - column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the host names of the cluster nodes - * processing the jobs. - */ - column = runningTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader()); - column.setMinWidth(NAME_COL_MIN_WIDTH); - column.setMaxWidth(NAME_COL_MAX_WIDTH); - column.setPreferredWidth(NAME_COL_PREFERRED_WIDTH); - column.setWidth(NAME_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the ingest activities associated with the - * jobs. - */ - column = runningTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader()); - column.setMinWidth(STAGE_COL_MIN_WIDTH); - column.setMaxWidth(STAGE_COL_MAX_WIDTH); - column.setPreferredWidth(STAGE_COL_PREFERRED_WIDTH); - column.setWidth(STAGE_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the ingest activity times associated with - * the jobs. - */ - column = runningTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader()); - column.setCellRenderer(new DurationCellRenderer()); - column.setMinWidth(GENERIC_COL_MIN_WIDTH); - column.setMaxWidth(STAGE_TIME_COL_MAX_WIDTH); - column.setPreferredWidth(STAGE_TIME_COL_MIN_WIDTH); - column.setWidth(STAGE_TIME_COL_MIN_WIDTH); - - /* - * Prevent sorting when a column header is clicked. - */ - runningTable.setAutoCreateRowSorter(false); - } - - /** - * Sets up the JTable that presents a view of the completed jobs list for an - * auto ingest cluster. - */ - private void initCompletedJobsTable() { - /* - * Remove some of the jobs table model columns from the JTable. This - * does not remove the columns from the model, just from this table. - */ - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); - completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); - /* - * Set up a column to display the cases associated with the jobs. - */ - TableColumn column; - column = completedTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); - column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); - column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); - column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); - column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the image folders associated with the - * jobs. - */ - column = completedTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); - column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); - column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); - column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); - column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the create times of the jobs. - */ - column = completedTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); - column.setCellRenderer(new LongDateCellRenderer()); - column.setMinWidth(TIME_COL_MIN_WIDTH); - column.setMaxWidth(TIME_COL_MAX_WIDTH); - column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - column.setWidth(TIME_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the completed times of the jobs. - */ - column = completedTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader()); - column.setCellRenderer(new LongDateCellRenderer()); - column.setMinWidth(TIME_COL_MIN_WIDTH); - column.setMaxWidth(TIME_COL_MAX_WIDTH); - column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - column.setWidth(TIME_COL_PREFERRED_WIDTH); - - /* - * Set up a column to display the statuses of the jobs, with a cell - * renderer that will choose an icon to represent the job status. - */ - column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); - column.setCellRenderer(new StatusIconCellRenderer()); - column.setMinWidth(STATUS_COL_MIN_WIDTH); - column.setMaxWidth(STATUS_COL_MAX_WIDTH); - column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); - column.setWidth(STATUS_COL_PREFERRED_WIDTH); - /* - * Allow sorting when a column header is clicked. - */ - completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); - } - +// /** +// * Sets up the JTable that presents a view of the pending jobs queue for an +// * auto ingest cluster. +// */ +// private void initPendingJobsTable() { +// /* +// * Remove some of the jobs table model columns from the JTable. This +// * does not remove the columns from the model, just from this table. +// */ +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); +// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); +// +// /* +// * Set up a column to display the cases associated with the jobs. +// */ +// TableColumn column; +// column = pendingTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); +// column.setMinWidth(GENERIC_COL_MIN_WIDTH); +// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); +// column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); +// column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the data sources associated with the jobs. +// */ +// column = pendingTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); +// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); +// column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); +// column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the create times of the jobs. +// */ +// column = pendingTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); +// column.setCellRenderer(new LongDateCellRenderer()); +// column.setMinWidth(TIME_COL_MIN_WIDTH); +// column.setMaxWidth(TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); +// column.setWidth(TIME_COL_PREFERRED_WIDTH); +// +// column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); +// column.setCellRenderer(new PrioritizedIconCellRenderer()); +// column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); +// column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); +// column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); +// /* +// * Allow sorting when a column header is clicked. +// */ +// pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); +// +// /* +// * Create a row selection listener to enable/disable the Prioritize +// * button. +// */ +// pendingTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { +// if (e.getValueIsAdjusting()) { +// return; +// } +// int row = pendingTable.getSelectedRow(); +// +// boolean enablePrioritizeButtons = false; +// boolean enableDeprioritizeButtons = false; +// if (row >= 0 && row < pendingTable.getRowCount()) { +// enablePrioritizeButtons = true; +// enableDeprioritizeButtons = (Integer) pendingTableModel.getValueAt(row, JobsTableModelColumns.PRIORITY.ordinal()) > 0; +// } +// this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); +// this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); +// this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); +// this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); +// }); +// } +// /** +// * Sets up the JTable that presents a view of the running jobs list for an +// * auto ingest cluster. +// */ +// private void initRunningJobsTable() { +// /* +// * Remove some of the jobs table model columns from the JTable. This +// * does not remove the columns from the model, just from this table. +// */ +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); +// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); +// /* +// * Set up a column to display the cases associated with the jobs. +// */ +// TableColumn column; +// column = runningTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); +// column.setMinWidth(GENERIC_COL_MIN_WIDTH); +// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); +// column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); +// column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the image folders associated with the +// * jobs. +// */ +// column = runningTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); +// column.setMinWidth(GENERIC_COL_MIN_WIDTH); +// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); +// column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); +// column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the host names of the cluster nodes +// * processing the jobs. +// */ +// column = runningTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader()); +// column.setMinWidth(NAME_COL_MIN_WIDTH); +// column.setMaxWidth(NAME_COL_MAX_WIDTH); +// column.setPreferredWidth(NAME_COL_PREFERRED_WIDTH); +// column.setWidth(NAME_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the ingest activities associated with the +// * jobs. +// */ +// column = runningTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader()); +// column.setMinWidth(STAGE_COL_MIN_WIDTH); +// column.setMaxWidth(STAGE_COL_MAX_WIDTH); +// column.setPreferredWidth(STAGE_COL_PREFERRED_WIDTH); +// column.setWidth(STAGE_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the ingest activity times associated with +// * the jobs. +// */ +// column = runningTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader()); +// column.setCellRenderer(new DurationCellRenderer()); +// column.setMinWidth(GENERIC_COL_MIN_WIDTH); +// column.setMaxWidth(STAGE_TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(STAGE_TIME_COL_MIN_WIDTH); +// column.setWidth(STAGE_TIME_COL_MIN_WIDTH); +// +// /* +// * Prevent sorting when a column header is clicked. +// */ +// runningTable.setAutoCreateRowSorter(false); +// } +// /** +// * Sets up the JTable that presents a view of the completed jobs list for an +// * auto ingest cluster. +// */ +// private void initCompletedJobsTable() { +// /* +// * Remove some of the jobs table model columns from the JTable. This +// * does not remove the columns from the model, just from this table. +// */ +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); +// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); +// /* +// * Set up a column to display the cases associated with the jobs. +// */ +// TableColumn column; +// column = completedTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); +// column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); +// column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); +// column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the image folders associated with the +// * jobs. +// */ +// column = completedTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); +// column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); +// column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); +// column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the create times of the jobs. +// */ +// column = completedTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); +// column.setCellRenderer(new LongDateCellRenderer()); +// column.setMinWidth(TIME_COL_MIN_WIDTH); +// column.setMaxWidth(TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); +// column.setWidth(TIME_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the completed times of the jobs. +// */ +// column = completedTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader()); +// column.setCellRenderer(new LongDateCellRenderer()); +// column.setMinWidth(TIME_COL_MIN_WIDTH); +// column.setMaxWidth(TIME_COL_MAX_WIDTH); +// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); +// column.setWidth(TIME_COL_PREFERRED_WIDTH); +// +// /* +// * Set up a column to display the statuses of the jobs, with a cell +// * renderer that will choose an icon to represent the job status. +// */ +// column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); +// column.setCellRenderer(new StatusIconCellRenderer()); +// column.setMinWidth(STATUS_COL_MIN_WIDTH); +// column.setMaxWidth(STATUS_COL_MAX_WIDTH); +// column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); +// column.setWidth(STATUS_COL_PREFERRED_WIDTH); +// /* +// * Allow sorting when a column header is clicked. +// */ +// completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); +// } +// /** * Starts up the auto ingest monitor and adds this panel as an observer, * subscribes to services monitor events and starts a task to populate the @@ -437,10 +462,10 @@ final class AutoIngestDashboard extends JPanel implements Observer { private void startUp() throws AutoIngestMonitor.AutoIngestMonitorException { PropertyChangeListener propChangeListener = (PropertyChangeEvent evt) -> { - + String serviceDisplayName = ServicesMonitor.Service.valueOf(evt.getPropertyName()).toString(); String status = evt.getNewValue().toString(); - + if (status.equals(ServicesMonitor.ServiceStatus.UP.toString())) { status = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up"); LOGGER.log(Level.INFO, "Connection to {0} is up", serviceDisplayName); //NON-NLS @@ -450,23 +475,23 @@ final class AutoIngestDashboard extends JPanel implements Observer { } else { LOGGER.log(Level.INFO, "Status for {0} is {1}", new Object[]{serviceDisplayName, status}); //NON-NLS } - + // if the status update is for an existing service who's status hasn't changed - do nothing. if (statusByService.containsKey(serviceDisplayName) && status.equals(statusByService.get(serviceDisplayName))) { return; } - + statusByService.put(serviceDisplayName, status); displayServicesStatus(); }; - + // Subscribe to all multi-user services in order to display their status Set servicesList = new HashSet<>(); servicesList.add(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString()); - servicesList.add(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()); + servicesList.add(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString()); servicesList.add(ServicesMonitor.Service.MESSAGING.toString()); ServicesMonitor.getInstance().addSubscriber(servicesList, propChangeListener); - + autoIngestMonitor = new AutoIngestMonitor(); autoIngestMonitor.addObserver(this); autoIngestMonitor.startUp(); @@ -474,7 +499,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Override public void update(Observable observable, Object arg) { - EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); + // EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); } /** @@ -484,53 +509,53 @@ final class AutoIngestDashboard extends JPanel implements Observer { * @param jobsSnapshot The jobs snapshot. */ private void refreshTables(JobsSnapshot jobsSnapshot) { - List pendingJobs = jobsSnapshot.getPendingJobs(); - List runningJobs = jobsSnapshot.getRunningJobs(); - List completedJobs = jobsSnapshot.getCompletedJobs(); - pendingJobs.sort(new AutoIngestJob.PriorityComparator()); - runningJobs.sort(new AutoIngestJob.DataSourceFileNameComparator()); - completedJobs.sort(new AutoIngestJob.CompletedDateDescendingComparator()); - refreshTable(pendingJobs, pendingTable, pendingTableModel); - refreshTable(runningJobs, runningTable, runningTableModel); - refreshTable(completedJobs, completedTable, completedTableModel); - } - - /** - * Reloads the table model for an auto ingest jobs table and refreshes the - * JTable that uses the model. - * - * @param jobs The list of auto ingest jobs. - * @param tableModel The table model. - * @param comparator An optional comparator (may be null) for sorting the - * table model. - */ - private void refreshTable(List jobs, JTable table, DefaultTableModel tableModel) { - try { - Path currentRow = getSelectedEntry(table, tableModel); - tableModel.setRowCount(0); - for (AutoIngestJob job : jobs) { - AutoIngestJob.StageDetails status = job.getProcessingStageDetails(); - tableModel.addRow(new Object[]{ - job.getManifest().getCaseName(), // CASE - job.getManifest().getDataSourcePath().getFileName(), job.getProcessingHostName(), // HOST_NAME - job.getManifest().getDateFileCreated(), // CREATED_TIME - job.getProcessingStageStartDate(), // STARTED_TIME - job.getCompletedDate(), // COMPLETED_TIME - status.getDescription(), // STAGE - job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS - ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME - job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH - job.getManifest().getFilePath(), // MANIFEST_FILE_PATH - job.getPriority(), // PRIORITY - job - }); - } - setSelectedEntry(table, tableModel, currentRow); - } catch (Exception ex) { - LOGGER.log(Level.SEVERE, "Error refreshing table " + table.toString(), ex); - } + pendingJobsPanel.refresh(jobsSnapshot); + runningJobsPanel.refresh(jobsSnapshot); + finishedJobsPanel.refresh(jobsSnapshot); + // List runningJobs = jobsSnapshot.getRunningJobs(); + // List completedJobs = jobsSnapshot.getCompletedJobs(); + // runningJobs.sort(new AutoIngestJob.DataSourceFileNameComparator()); + // completedJobs.sort(new AutoIngestJob.CompletedDateDescendingComparator()); + // refreshTable(pendingJobs, pendingTable, pendingTableModel); +// refreshTable(runningJobs, runningTable, runningTableModel); + // refreshTable(completedJobs, completedTable, completedTableModel); } +// /** +// * Reloads the table model for an auto ingest jobs table and refreshes the +// * JTable that uses the model. +// * +// * @param jobs The list of auto ingest jobs. +// * @param tableModel The table model. +// * @param comparator An optional comparator (may be null) for sorting the +// * table model. +// */ +// private void refreshTable(List jobs, JTable table, DefaultTableModel tableModel) { +// try { +// Path currentRow = getSelectedEntry(table, tableModel); +// tableModel.setRowCount(0); +// for (AutoIngestJob job : jobs) { +// AutoIngestJob.StageDetails status = job.getProcessingStageDetails(); +// tableModel.addRow(new Object[]{ +// job.getManifest().getCaseName(), // CASE +// job.getManifest().getDataSourcePath().getFileName(), job.getProcessingHostName(), // HOST_NAME +// job.getManifest().getDateFileCreated(), // CREATED_TIME +// job.getProcessingStageStartDate(), // STARTED_TIME +// job.getCompletedDate(), // COMPLETED_TIME +// status.getDescription(), // STAGE +// job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS +// ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME +// job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH +// job.getManifest().getFilePath(), // MANIFEST_FILE_PATH +// job.getPriority(), // PRIORITY +// job +// }); +// } +// setSelectedEntry(table, tableModel, currentRow); +// } catch (Exception ex) { +// LOGGER.log(Level.SEVERE, "Error refreshing table " + table.toString(), ex); +// } +// } /** * Gets a path representing the current selection in a table. * @@ -629,7 +654,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { JOB.getColumnHeader() }; }; - /** * A task that refreshes the UI components on this panel to reflect a * snapshot of the pending, running and completed auto ingest jobs lists of @@ -698,11 +722,8 @@ final class AutoIngestDashboard extends JPanel implements Observer { jButton1 = new javax.swing.JButton(); pendingScrollPane = new javax.swing.JScrollPane(); - pendingTable = new javax.swing.JTable(); runningScrollPane = new javax.swing.JScrollPane(); - runningTable = new javax.swing.JTable(); completedScrollPane = new javax.swing.JScrollPane(); - completedTable = new javax.swing.JTable(); lbPending = new javax.swing.JLabel(); lbRunning = new javax.swing.JLabel(); lbCompleted = new javax.swing.JLabel(); @@ -717,56 +738,10 @@ final class AutoIngestDashboard extends JPanel implements Observer { org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N - pendingTable.setModel(pendingTableModel); - pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N - pendingTable.setRowHeight(20); - pendingTable.setSelectionModel(new DefaultListSelectionModel() { - private static final long serialVersionUID = 1L; - @Override - public void setSelectionInterval(int index0, int index1) { - if (index0 == pendingTable.getSelectedRow()) { - pendingTable.clearSelection(); - } else { - super.setSelectionInterval(index0, index1); - } - } - }); - pendingTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - pendingScrollPane.setViewportView(pendingTable); - - runningTable.setModel(runningTableModel); - runningTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.runningTable.toolTipText")); // NOI18N - runningTable.setRowHeight(20); - runningTable.setSelectionModel(new DefaultListSelectionModel() { - private static final long serialVersionUID = 1L; - @Override - public void setSelectionInterval(int index0, int index1) { - if (index0 == runningTable.getSelectedRow()) { - runningTable.clearSelection(); - } else { - super.setSelectionInterval(index0, index1); - } - } - }); - runningTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - runningScrollPane.setViewportView(runningTable); - - completedTable.setModel(completedTableModel); - completedTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.completedTable.toolTipText")); // NOI18N - completedTable.setRowHeight(20); - completedTable.setSelectionModel(new DefaultListSelectionModel() { - private static final long serialVersionUID = 1L; - @Override - public void setSelectionInterval(int index0, int index1) { - if (index0 == completedTable.getSelectedRow()) { - completedTable.clearSelection(); - } else { - super.setSelectionInterval(index0, index1); - } - } - }); - completedTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - completedScrollPane.setViewportView(completedTable); + pendingScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + pendingScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + pendingScrollPane.setOpaque(false); + pendingScrollPane.setPreferredSize(new java.awt.Dimension(2, 215)); lbPending.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(lbPending, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbPending.text")); // NOI18N @@ -843,7 +818,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(pendingScrollPane) + .addComponent(pendingScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() @@ -883,7 +858,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbPending, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(1, 1, 1) - .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(lbRunning) .addGap(1, 1, 1) @@ -920,38 +895,38 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Messages({"AutoIngestDashboard.errorMessage.jobPrioritization=Failed to prioritize job \"%s\"."}) private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.prioritizeJob(job); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), job.getManifest().getFilePath()); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } +// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { +// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); +// AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); +// JobsSnapshot jobsSnapshot; +// try { +// jobsSnapshot = autoIngestMonitor.prioritizeJob(job); +// refreshTables(jobsSnapshot); +// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { +// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), job.getManifest().getFilePath()); +// LOGGER.log(Level.SEVERE, errorMessage, ex); +// MessageNotifyUtil.Message.error(errorMessage); +// } +// setCursor(Cursor.getDefaultCursor()); +// } }//GEN-LAST:event_prioritizeJobButtonActionPerformed @Messages({"AutoIngestDashboard.errorMessage.casePrioritization=Failed to prioritize case \"%s\"."}) private void prioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeCaseButtonActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.prioritizeCase(caseName); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), caseName); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } +// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { +// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); +// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); +// JobsSnapshot jobsSnapshot; +// try { +// jobsSnapshot = autoIngestMonitor.prioritizeCase(caseName); +// refreshTables(jobsSnapshot); +// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { +// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), caseName); +// LOGGER.log(Level.SEVERE, errorMessage, ex); +// MessageNotifyUtil.Message.error(errorMessage); +// } +// setCursor(Cursor.getDefaultCursor()); +// } }//GEN-LAST:event_prioritizeCaseButtonActionPerformed private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed @@ -960,44 +935,43 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Messages({"AutoIngestDashboard.errorMessage.jobDeprioritization=Failed to deprioritize job \"%s\"."}) private void deprioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeJobButtonActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.deprioritizeJob(job); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), job.getManifest().getFilePath()); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } +// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { +// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); +// AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); +// JobsSnapshot jobsSnapshot; +// try { +// jobsSnapshot = autoIngestMonitor.deprioritizeJob(job); +// refreshTables(jobsSnapshot); +// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { +// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), job.getManifest().getFilePath()); +// LOGGER.log(Level.SEVERE, errorMessage, ex); +// MessageNotifyUtil.Message.error(errorMessage); +// } +// setCursor(Cursor.getDefaultCursor()); +// } }//GEN-LAST:event_deprioritizeJobButtonActionPerformed @Messages({"AutoIngestDashboard.errorMessage.caseDeprioritization=Failed to deprioritize case \"%s\"."}) private void deprioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeCaseButtonActionPerformed - if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.deprioritizeCase(caseName); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), caseName); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } +// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { +// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); +// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); +// JobsSnapshot jobsSnapshot; +// try { +// jobsSnapshot = autoIngestMonitor.deprioritizeCase(caseName); +// refreshTables(jobsSnapshot); +// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { +// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), caseName); +// LOGGER.log(Level.SEVERE, errorMessage, ex); +// MessageNotifyUtil.Message.error(errorMessage); +// } +// setCursor(Cursor.getDefaultCursor()); +// } }//GEN-LAST:event_deprioritizeCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; - private javax.swing.JTable completedTable; private javax.swing.JButton deprioritizeCaseButton; private javax.swing.JButton deprioritizeJobButton; private javax.swing.JButton jButton1; @@ -1006,42 +980,40 @@ final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JLabel lbRunning; private javax.swing.JLabel lbServicesStatus; private javax.swing.JScrollPane pendingScrollPane; - private javax.swing.JTable pendingTable; private javax.swing.JButton prioritizeCaseButton; private javax.swing.JButton prioritizeJobButton; private javax.swing.JButton refreshButton; private javax.swing.JScrollPane runningScrollPane; - private javax.swing.JTable runningTable; private javax.swing.JTextField tbServicesStatusMessage; // End of variables declaration//GEN-END:variables - private class AutoIngestTableModel extends DefaultTableModel { - - private static final long serialVersionUID = 1L; - - private AutoIngestTableModel(String[] headers, int i) { - super(headers, i); - } - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - @Override - public Class getColumnClass(int columnIndex) { - if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { - return Integer.class; - } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() - || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() - || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() - || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { - return Date.class; - } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { - return Boolean.class; - } else { - return super.getColumnClass(columnIndex); - } - } - } +// private class AutoIngestTableModel extends DefaultTableModel { +// +// private static final long serialVersionUID = 1L; +// +// private AutoIngestTableModel(String[] headers, int i) { +// super(headers, i); +// } +// +// @Override +// public boolean isCellEditable(int row, int column) { +// return false; +// } +// +// @Override +// public Class getColumnClass(int columnIndex) { +// if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { +// return Integer.class; +// } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() +// || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() +// || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() +// || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { +// return Date.class; +// } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { +// return Boolean.class; +// } else { +// return super.getColumnClass(columnIndex); +// } +// } +// } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.form new file mode 100644 index 0000000000..bde4db4324 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.form @@ -0,0 +1,18 @@ + + +
+ + + + + + + + + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java new file mode 100644 index 0000000000..e37f419802 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -0,0 +1,173 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.experimental.autoingest; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionListener; +import javax.swing.SwingWorker; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.explorer.ExplorerManager; +import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.datamodel.EmptyNode; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; + +/** + * + * @author wschaefer + */ +final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerManager.Provider { + + private static final long serialVersionUID = 1L; + private final org.openide.explorer.view.OutlineView outlineView; + private final Outline outline; + private ExplorerManager explorerManager; + private JobListWorker jobListWorker; + private final AutoIngestJobType type; + + /** + * Creates new form PendingJobsPanel + */ + AutoIngestJobsPanel(AutoIngestJobType jobType) { + initComponents(); + type = jobType; + outlineView = new org.openide.explorer.view.OutlineView(); + outline = outlineView.getOutline(); + customize(); + } + + void customize() { + + switch (type) { + case PENDING_JOB: + outlineView.setPropertyColumns(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), + Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), + Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text()); + break; + case RUNNING_JOB: + outlineView.setPropertyColumns("Stage", "Stage"); + break; + case COMPLETED_JOB: + outlineView.setPropertyColumns(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), + "Date Started", "Date Started", + "Date Completed", "Date Completed", + "Status", "Status"); + break; + default: + } + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestNode_col1_text()); + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + outline.setRootVisible(false); + outline.setColumnSorted(0, false, 1); + if (null == explorerManager) { + explorerManager = new ExplorerManager(); + + } + outline.setRowSelectionAllowed(false); + + // outlineView.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + add(outlineView, java.awt.BorderLayout.CENTER); + + } + + @Override + public void setSize(Dimension d) { + super.setSize(d); + outlineView.setMaximumSize(new Dimension(400, 100)); + outline.setPreferredScrollableViewportSize(new Dimension(400, 100)); + } + + void addListSelectionListener(ListSelectionListener listener) { + outline.getSelectionModel().addListSelectionListener(listener); + } + + @Override + public ExplorerManager getExplorerManager() { + return explorerManager; + } + + void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { + if (jobListWorker == null || jobListWorker.isDone()) { + outline.setRowSelectionAllowed(false); +// EmptyNode emptyNode = new EmptyNode("Refreshing..."); +// explorerManager.setRootContext(emptyNode); + jobListWorker = new JobListWorker(jobsSnapshot, type); + jobListWorker.execute(); + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + setLayout(new java.awt.BorderLayout()); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + /** + * Swingworker to fetch the updated List of cases in a background thread + */ + private class JobListWorker extends SwingWorker, Void> { + + private final AutoIngestMonitor.JobsSnapshot jobsSnapshot; + private final AutoIngestJobType jobType; + + JobListWorker(AutoIngestMonitor.JobsSnapshot snapshot, AutoIngestJobType type) { + jobsSnapshot = snapshot; + jobType = type; + } + + @Override + protected List doInBackground() throws Exception { + List jobs; + switch (jobType) { + case PENDING_JOB: + jobs = jobsSnapshot.getPendingJobs(); + break; + case RUNNING_JOB: + jobs = jobsSnapshot.getRunningJobs(); + break; + case COMPLETED_JOB: + jobs = jobsSnapshot.getCompletedJobs(); + break; + default: + jobs = new ArrayList<>(); + + } + jobs.sort(new AutoIngestJob.PriorityComparator()); + return jobs; + } + + @Override + protected void done() { + try { + List jobs = get(); + EventQueue.invokeLater(() -> { + AutoIngestNode autoIngestNode = new AutoIngestNode(jobs, jobType); + explorerManager.setRootContext(autoIngestNode); + outline.setRowSelectionAllowed(true); + }); + } catch (InterruptedException | ExecutionException ex) { + Exceptions.printStackTrace(ex); + } + + } + } + +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java new file mode 100644 index 0000000000..e436ab03bc --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java @@ -0,0 +1,134 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.experimental.autoingest; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; + +final class AutoIngestNode extends AbstractNode { + + @Messages({ + "AutoIngestNode.col1.text=Case Name", + "AutoIngestNode.col2.text=File Name", + "AutoIngestNode.col3.text=Date Created", + "AutoIngestNode.col4.text=Priority" + }) + + AutoIngestNode(List jobs, AutoIngestJobType type) { + super(Children.create(new AutoIngestNodeChildren(jobs, type), true)); + } + + static class AutoIngestNodeChildren extends ChildFactory { + + AutoIngestJobType autoIngestJobType; + private final List jobs; + + AutoIngestNodeChildren(List jobList, AutoIngestJobType type) { + this.jobs = jobList; + autoIngestJobType = type; + } + + @Override + protected boolean createKeys(List list) { + if (jobs != null && jobs.size() > 0) { + list.addAll(jobs); + } + return true; + } + + @Override + protected Node createNodeForKey(AutoIngestJob key) { + return new PendingJobNode(key, autoIngestJobType); + } + + } + + /** + * A node which represents a single multi user case. + */ + static final class PendingJobNode extends AbstractNode { + + private final AutoIngestJob autoIngestJob; + private final String caseName; + private final Path fileName; + private final Date dateCreated; + private final int priority; + private final AutoIngestJobType jobType; + + PendingJobNode(AutoIngestJob job, AutoIngestJobType type) { + super(Children.LEAF); + jobType = type; + autoIngestJob = job; + caseName = autoIngestJob.getManifest().getCaseName(); + fileName = autoIngestJob.getManifest().getDataSourcePath().getFileName(); + dateCreated = autoIngestJob.getManifest().getDateFileCreated(); + priority = autoIngestJob.getPriority(); + super.setName(caseName); + setName(caseName); + setDisplayName(caseName); + } + + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), caseName)); + switch (jobType) { + case PENDING_JOB: + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), fileName.toString())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Integer.toString(priority))); + break; + case RUNNING_JOB: + AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); + ss.put(new NodeProperty<>("Stage", "Stage", "Stage", status.getDescription())); + break; + case COMPLETED_JOB: + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); + ss.put(new NodeProperty<>("Date Started", "Date Started", "Date Started", autoIngestJob.getProcessingStageStartDate())); + ss.put(new NodeProperty<>("Date Completed - Prop6", "Date Completed", "Date Completed - Prop6", autoIngestJob.getCompletedDate())); + ss.put(new NodeProperty<>("Status", "Status", "Status", autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); + break; + default: + } +// AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); + // ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), caseName)); +// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), fileName.toString())); +// ss.put(new NodeProperty<>("Host Name - Prop3", "Host Name - Prop3", "Host Name - Prop3", autoIngestJob.getProcessingHostName())); +// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); +// ss.put(new NodeProperty<>("Date Started - Prop5", "Date Started - Prop5", "Date Started - Prop5", autoIngestJob.getProcessingStageStartDate())); +// ss.put(new NodeProperty<>("Date Completed - Prop6", "Date Completed - Prop6", "Date Completed - Prop6", autoIngestJob.getCompletedDate())); +// ss.put(new NodeProperty<>("Stage - Prop7", "Stage - Prop7", "Stage - Prop7", status.getDescription())); +// ss.put(new NodeProperty<>("Status - Prop8", "Status - Prop8", "Status - Prop8", autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); +// ss.put(new NodeProperty<>("Stage Time - Prop9", "Stage Time - Prop9", "Stage Time - Prop9", (Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime()))); +// ss.put(new NodeProperty<>("Case Directory - Prop10", "Case Directory - Prop10", "Case Directory - Prop10", autoIngestJob.getCaseDirectoryPath())); +// ss.put(new NodeProperty<>("Manifest Path - Prop11", "Manifest Path - Prop11", "Manifest Path - Prop11", autoIngestJob.getManifest().getFilePath())); +// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Integer.toString(priority))); + return s; + } + + } + + enum AutoIngestJobType { + PENDING_JOB, //NON-NLS + RUNNING_JOB, //NON-NLS + COMPLETED_JOB //NON-NLS + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index 633d069cc8..a9a500a5b9 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -10,9 +10,6 @@ AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime=Job Completed AutoIngestDashboard.JobsTableModel.ColumnHeader.Stage=Stage AutoIngestDashboard.JobsTableModel.ColumnHeader.Status=Status AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath= Manifest File Path -AutoIngestDashboard.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first -AutoIngestDashboard.runningTable.toolTipText=The Running table displays the currently running Job and information about it -AutoIngestDashboard.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already AutoIngestDashboard.JobsTableModel.ColumnHeader.StageTime=Time in Stage AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder=Case AutoIngestDashboard.JobsTableModel.ColumnHeader.Job=Job From b6ccca3e57a92ca2109c765160553b281c65825f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 5 Apr 2018 14:08:29 -0400 Subject: [PATCH 05/64] 3610 - re-enable buttons on Auto Ingest Dashboard with outlineViews --- .../autoingest/AutoIngestDashboard.java | 620 ++++-------------- .../autoingest/AutoIngestJobsPanel.java | 53 +- .../autoingest/AutoIngestNode.java | 96 +-- 3 files changed, 195 insertions(+), 574 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index fb5abdc686..43d0d791d4 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -19,45 +19,26 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Cursor; -import java.awt.EventQueue; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Instant; -import java.util.Date; -import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.logging.Level; -import javax.swing.DefaultListSelectionModel; import java.awt.Color; +import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; import javax.swing.JPanel; -import javax.swing.JTable; -import javax.swing.ListSelectionModel; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.table.DefaultTableModel; -import org.netbeans.swing.outline.Outline; -import org.openide.explorer.ExplorerManager; -import javax.swing.table.TableColumn; -import org.netbeans.swing.outline.DefaultOutlineModel; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.EmptyNode; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; -import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; -import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; -import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A dashboard for monitoring an automated ingest cluster. @@ -89,9 +70,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { private static final int COMPLETED_TIME_COL_MAX_WIDTH = 2000; private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280; private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboard.class.getName()); - // private final DefaultTableModel pendingTableModel; -// private final DefaultTableModel runningTableModel; -// private final DefaultTableModel completedTableModel; private AutoIngestMonitor autoIngestMonitor; private AutoIngestJobsPanel pendingJobsPanel; private AutoIngestJobsPanel runningJobsPanel; @@ -126,37 +104,53 @@ final class AutoIngestDashboard extends JPanel implements Observer { private AutoIngestDashboard() { this.statusByService = new ConcurrentHashMap<>(); -// pendingTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); -// runningTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); -// completedTableModel = new AutoIngestTableModel(JobsTableModelColumns.headers, 0); initComponents(); statusByService.put(ServicesMonitor.Service.REMOTE_CASE_DATABASE.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.MESSAGING.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); setServicesStatusMessage(); - // initPendingJobsTable(); -// initRunningJobsTable(); -// initCompletedJobsTable(); pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.PENDING_JOB); pendingJobsPanel.setSize(pendingScrollPane.getSize()); pendingScrollPane.add(pendingJobsPanel); pendingScrollPane.setViewportView(pendingJobsPanel); pendingJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - System.out.println("SELECTION HAPPENED PENDING WJS-TODO"); + if (e.getValueIsAdjusting()) { + return; + } + AutoIngestJob job = this.pendingJobsPanel.getSelectedAutoIngestJob(); + + boolean enablePrioritizeButtons = false; + boolean enableDeprioritizeButtons = false; + if (job != null) { + enablePrioritizeButtons = true; + enableDeprioritizeButtons = job.getPriority() > 0; + } + this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); + this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); + this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); + this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); }); runningJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.RUNNING_JOB); runningJobsPanel.setSize(runningScrollPane.getSize()); runningScrollPane.add(runningJobsPanel); runningScrollPane.setViewportView(runningJobsPanel); runningJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - System.out.println("SELECTION HAPPENED RUNNING WJS-TODO"); + boolean enabled = false; + this.prioritizeJobButton.setEnabled(enabled); + this.prioritizeCaseButton.setEnabled(enabled); + this.deprioritizeJobButton.setEnabled(enabled); + this.deprioritizeCaseButton.setEnabled(enabled); }); finishedJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.COMPLETED_JOB); finishedJobsPanel.setSize(completedScrollPane.getSize()); completedScrollPane.add(finishedJobsPanel); completedScrollPane.setViewportView(finishedJobsPanel); finishedJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - System.out.println("SELECTION HAPPENED COMPLETED WJS-TODO"); + boolean enabled = false; + this.prioritizeJobButton.setEnabled(enabled); + this.prioritizeCaseButton.setEnabled(enabled); + this.deprioritizeJobButton.setEnabled(enabled); + this.deprioritizeCaseButton.setEnabled(enabled); }); /* * Must set this flag, otherwise pop up menus don't close properly. @@ -229,231 +223,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { }.execute(); } -// /** -// * Sets up the JTable that presents a view of the pending jobs queue for an -// * auto ingest cluster. -// */ -// private void initPendingJobsTable() { -// /* -// * Remove some of the jobs table model columns from the JTable. This -// * does not remove the columns from the model, just from this table. -// */ -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); -// pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); -// -// /* -// * Set up a column to display the cases associated with the jobs. -// */ -// TableColumn column; -// column = pendingTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); -// column.setMinWidth(GENERIC_COL_MIN_WIDTH); -// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); -// column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); -// column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the data sources associated with the jobs. -// */ -// column = pendingTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); -// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); -// column.setPreferredWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); -// column.setWidth(PENDING_TABLE_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the create times of the jobs. -// */ -// column = pendingTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); -// column.setCellRenderer(new LongDateCellRenderer()); -// column.setMinWidth(TIME_COL_MIN_WIDTH); -// column.setMaxWidth(TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); -// column.setWidth(TIME_COL_PREFERRED_WIDTH); -// -// column = pendingTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()); -// column.setCellRenderer(new PrioritizedIconCellRenderer()); -// column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH); -// column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); -// column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH); -// /* -// * Allow sorting when a column header is clicked. -// */ -// pendingTable.setRowSorter(new AutoIngestRowSorter<>(pendingTableModel)); -// -// /* -// * Create a row selection listener to enable/disable the Prioritize -// * button. -// */ -// pendingTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { -// if (e.getValueIsAdjusting()) { -// return; -// } -// int row = pendingTable.getSelectedRow(); -// -// boolean enablePrioritizeButtons = false; -// boolean enableDeprioritizeButtons = false; -// if (row >= 0 && row < pendingTable.getRowCount()) { -// enablePrioritizeButtons = true; -// enableDeprioritizeButtons = (Integer) pendingTableModel.getValueAt(row, JobsTableModelColumns.PRIORITY.ordinal()) > 0; -// } -// this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); -// this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); -// this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); -// this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); -// }); -// } -// /** -// * Sets up the JTable that presents a view of the running jobs list for an -// * auto ingest cluster. -// */ -// private void initRunningJobsTable() { -// /* -// * Remove some of the jobs table model columns from the JTable. This -// * does not remove the columns from the model, just from this table. -// */ -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); -// runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); -// /* -// * Set up a column to display the cases associated with the jobs. -// */ -// TableColumn column; -// column = runningTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); -// column.setMinWidth(GENERIC_COL_MIN_WIDTH); -// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); -// column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); -// column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the image folders associated with the -// * jobs. -// */ -// column = runningTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); -// column.setMinWidth(GENERIC_COL_MIN_WIDTH); -// column.setMaxWidth(GENERIC_COL_MAX_WIDTH); -// column.setPreferredWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); -// column.setWidth(RUNNING_TABLE_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the host names of the cluster nodes -// * processing the jobs. -// */ -// column = runningTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader()); -// column.setMinWidth(NAME_COL_MIN_WIDTH); -// column.setMaxWidth(NAME_COL_MAX_WIDTH); -// column.setPreferredWidth(NAME_COL_PREFERRED_WIDTH); -// column.setWidth(NAME_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the ingest activities associated with the -// * jobs. -// */ -// column = runningTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader()); -// column.setMinWidth(STAGE_COL_MIN_WIDTH); -// column.setMaxWidth(STAGE_COL_MAX_WIDTH); -// column.setPreferredWidth(STAGE_COL_PREFERRED_WIDTH); -// column.setWidth(STAGE_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the ingest activity times associated with -// * the jobs. -// */ -// column = runningTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader()); -// column.setCellRenderer(new DurationCellRenderer()); -// column.setMinWidth(GENERIC_COL_MIN_WIDTH); -// column.setMaxWidth(STAGE_TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(STAGE_TIME_COL_MIN_WIDTH); -// column.setWidth(STAGE_TIME_COL_MIN_WIDTH); -// -// /* -// * Prevent sorting when a column header is clicked. -// */ -// runningTable.setAutoCreateRowSorter(false); -// } -// /** -// * Sets up the JTable that presents a view of the completed jobs list for an -// * auto ingest cluster. -// */ -// private void initCompletedJobsTable() { -// /* -// * Remove some of the jobs table model columns from the JTable. This -// * does not remove the columns from the model, just from this table. -// */ -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STARTED_TIME.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.STAGE_TIME.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.HOST_NAME.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.JOB.getColumnHeader())); -// completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader())); -// /* -// * Set up a column to display the cases associated with the jobs. -// */ -// TableColumn column; -// column = completedTable.getColumn(JobsTableModelColumns.CASE.getColumnHeader()); -// column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); -// column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); -// column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the image folders associated with the -// * jobs. -// */ -// column = completedTable.getColumn(JobsTableModelColumns.DATA_SOURCE.getColumnHeader()); -// column.setMinWidth(COMPLETED_TIME_COL_MIN_WIDTH); -// column.setMaxWidth(COMPLETED_TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); -// column.setWidth(COMPLETED_TIME_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the create times of the jobs. -// */ -// column = completedTable.getColumn(JobsTableModelColumns.CREATED_TIME.getColumnHeader()); -// column.setCellRenderer(new LongDateCellRenderer()); -// column.setMinWidth(TIME_COL_MIN_WIDTH); -// column.setMaxWidth(TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); -// column.setWidth(TIME_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the completed times of the jobs. -// */ -// column = completedTable.getColumn(JobsTableModelColumns.COMPLETED_TIME.getColumnHeader()); -// column.setCellRenderer(new LongDateCellRenderer()); -// column.setMinWidth(TIME_COL_MIN_WIDTH); -// column.setMaxWidth(TIME_COL_MAX_WIDTH); -// column.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); -// column.setWidth(TIME_COL_PREFERRED_WIDTH); -// -// /* -// * Set up a column to display the statuses of the jobs, with a cell -// * renderer that will choose an icon to represent the job status. -// */ -// column = completedTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()); -// column.setCellRenderer(new StatusIconCellRenderer()); -// column.setMinWidth(STATUS_COL_MIN_WIDTH); -// column.setMaxWidth(STATUS_COL_MAX_WIDTH); -// column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); -// column.setWidth(STATUS_COL_PREFERRED_WIDTH); -// /* -// * Allow sorting when a column header is clicked. -// */ -// completedTable.setRowSorter(new AutoIngestRowSorter<>(completedTableModel)); -// } -// /** * Starts up the auto ingest monitor and adds this panel as an observer, * subscribes to services monitor events and starts a task to populate the @@ -499,7 +268,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Override public void update(Observable observable, Object arg) { - // EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); + EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); } /** @@ -512,172 +281,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { pendingJobsPanel.refresh(jobsSnapshot); runningJobsPanel.refresh(jobsSnapshot); finishedJobsPanel.refresh(jobsSnapshot); - // List runningJobs = jobsSnapshot.getRunningJobs(); - // List completedJobs = jobsSnapshot.getCompletedJobs(); - // runningJobs.sort(new AutoIngestJob.DataSourceFileNameComparator()); - // completedJobs.sort(new AutoIngestJob.CompletedDateDescendingComparator()); - // refreshTable(pendingJobs, pendingTable, pendingTableModel); -// refreshTable(runningJobs, runningTable, runningTableModel); - // refreshTable(completedJobs, completedTable, completedTableModel); - } - -// /** -// * Reloads the table model for an auto ingest jobs table and refreshes the -// * JTable that uses the model. -// * -// * @param jobs The list of auto ingest jobs. -// * @param tableModel The table model. -// * @param comparator An optional comparator (may be null) for sorting the -// * table model. -// */ -// private void refreshTable(List jobs, JTable table, DefaultTableModel tableModel) { -// try { -// Path currentRow = getSelectedEntry(table, tableModel); -// tableModel.setRowCount(0); -// for (AutoIngestJob job : jobs) { -// AutoIngestJob.StageDetails status = job.getProcessingStageDetails(); -// tableModel.addRow(new Object[]{ -// job.getManifest().getCaseName(), // CASE -// job.getManifest().getDataSourcePath().getFileName(), job.getProcessingHostName(), // HOST_NAME -// job.getManifest().getDateFileCreated(), // CREATED_TIME -// job.getProcessingStageStartDate(), // STARTED_TIME -// job.getCompletedDate(), // COMPLETED_TIME -// status.getDescription(), // STAGE -// job.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, // STATUS -// ((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // STAGE_TIME -// job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH -// job.getManifest().getFilePath(), // MANIFEST_FILE_PATH -// job.getPriority(), // PRIORITY -// job -// }); -// } -// setSelectedEntry(table, tableModel, currentRow); -// } catch (Exception ex) { -// LOGGER.log(Level.SEVERE, "Error refreshing table " + table.toString(), ex); -// } -// } - /** - * Gets a path representing the current selection in a table. - * - * @param table The table. - * @param tableModel The table model of the table. - * - * @return A path representing the current selection, or null if there is no - * selection. - */ - Path getSelectedEntry(JTable table, DefaultTableModel tableModel) { - try { - int currentlySelectedRow = table.getSelectedRow(); - if (currentlySelectedRow >= 0 && currentlySelectedRow < table.getRowCount()) { - return Paths.get(tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(currentlySelectedRow, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); - } - } catch (Exception ignored) { - return null; - } - return null; - } - - /** - * Sets the selection of the table to the passed-in path's item, if that - * item exists in the table. If it does not, clears the table selection. - * - * @param table The table. - * @param tableModel The table model of the table. - * @param path The path of the item to set - */ - void setSelectedEntry(JTable table, DefaultTableModel tableModel, Path path) { - if (path != null) { - try { - for (int row = 0; row < table.getRowCount(); ++row) { - Path temp = Paths.get(tableModel.getValueAt(row, JobsTableModelColumns.CASE.ordinal()).toString(), - tableModel.getValueAt(row, JobsTableModelColumns.DATA_SOURCE.ordinal()).toString()); - if (temp.compareTo(path) == 0) { // found it - table.setRowSelectionInterval(row, row); - return; - } - } - } catch (Exception ignored) { - table.clearSelection(); - } - } - table.clearSelection(); - } - - /* - * This enum is used in conjunction with the DefaultTableModel class to - * provide table models for the JTables used to display a view of the - * pending jobs queue, running jobs list, and completed jobs list for an - * auto ingest cluster. The enum allows the columns of the table model to be - * described by either an enum ordinal or a column header string. - */ - private enum JobsTableModelColumns { - @Messages({"AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority=Prioritized"}) - - CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")), - DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")), - HOST_NAME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")), - CREATED_TIME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CreatedTime")), - STARTED_TIME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.StartedTime")), - COMPLETED_TIME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime")), - STAGE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Stage")), - STAGE_TIME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.StageTime")), - STATUS(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Status")), - CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.CaseFolder")), - MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath")), - PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Priority")), - JOB(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Job")); - - private final String header; - - private JobsTableModelColumns(String header) { - this.header = header; - } - - private String getColumnHeader() { - return header; - } - - private static final String[] headers = { - CASE.getColumnHeader(), - DATA_SOURCE.getColumnHeader(), - HOST_NAME.getColumnHeader(), - CREATED_TIME.getColumnHeader(), - STARTED_TIME.getColumnHeader(), - COMPLETED_TIME.getColumnHeader(), - STAGE.getColumnHeader(), - STATUS.getColumnHeader(), - STAGE_TIME.getColumnHeader(), - CASE_DIRECTORY_PATH.getColumnHeader(), - MANIFEST_FILE_PATH.getColumnHeader(), - PRIORITY.getColumnHeader(), - JOB.getColumnHeader() - }; - }; - /** - * A task that refreshes the UI components on this panel to reflect a - * snapshot of the pending, running and completed auto ingest jobs lists of - * an auto ingest cluster. - */ - private class RefreshComponentsTask implements Runnable { - - private final JobsSnapshot jobsSnapshot; - - /** - * Constructs a task that refreshes the UI components on this panel to - * reflect a snapshot of the pending, running and completed auto ingest - * jobs lists of an auto ingest cluster. - * - * @param jobsSnapshot The jobs snapshot. - */ - RefreshComponentsTask(JobsSnapshot jobsSnapshot) { - this.jobsSnapshot = jobsSnapshot; - } - - @Override - public void run() { - refreshTables(jobsSnapshot); - } } /** @@ -895,38 +498,39 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Messages({"AutoIngestDashboard.errorMessage.jobPrioritization=Failed to prioritize job \"%s\"."}) private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed -// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { -// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); -// AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); -// JobsSnapshot jobsSnapshot; -// try { -// jobsSnapshot = autoIngestMonitor.prioritizeJob(job); -// refreshTables(jobsSnapshot); -// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { -// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), job.getManifest().getFilePath()); -// LOGGER.log(Level.SEVERE, errorMessage, ex); -// MessageNotifyUtil.Message.error(errorMessage); -// } -// setCursor(Cursor.getDefaultCursor()); -// } + AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); + if (job != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + JobsSnapshot jobsSnapshot; + try { + jobsSnapshot = autoIngestMonitor.prioritizeJob(job); + refreshTables(jobsSnapshot); + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), job.getManifest().getFilePath()); + LOGGER.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } + setCursor(Cursor.getDefaultCursor()); + } }//GEN-LAST:event_prioritizeJobButtonActionPerformed @Messages({"AutoIngestDashboard.errorMessage.casePrioritization=Failed to prioritize case \"%s\"."}) private void prioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeCaseButtonActionPerformed -// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { -// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); -// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); -// JobsSnapshot jobsSnapshot; -// try { -// jobsSnapshot = autoIngestMonitor.prioritizeCase(caseName); -// refreshTables(jobsSnapshot); -// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { -// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), caseName); -// LOGGER.log(Level.SEVERE, errorMessage, ex); -// MessageNotifyUtil.Message.error(errorMessage); -// } -// setCursor(Cursor.getDefaultCursor()); -// } + AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); + if (job != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + String caseName = job.getManifest().getCaseName(); + JobsSnapshot jobsSnapshot; + try { + jobsSnapshot = autoIngestMonitor.prioritizeCase(caseName); + refreshTables(jobsSnapshot); + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), caseName); + LOGGER.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } + setCursor(Cursor.getDefaultCursor()); + } }//GEN-LAST:event_prioritizeCaseButtonActionPerformed private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed @@ -935,38 +539,39 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Messages({"AutoIngestDashboard.errorMessage.jobDeprioritization=Failed to deprioritize job \"%s\"."}) private void deprioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeJobButtonActionPerformed -// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { -// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); -// AutoIngestJob job = (AutoIngestJob) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.JOB.ordinal())); -// JobsSnapshot jobsSnapshot; -// try { -// jobsSnapshot = autoIngestMonitor.deprioritizeJob(job); -// refreshTables(jobsSnapshot); -// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { -// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), job.getManifest().getFilePath()); -// LOGGER.log(Level.SEVERE, errorMessage, ex); -// MessageNotifyUtil.Message.error(errorMessage); -// } -// setCursor(Cursor.getDefaultCursor()); -// } + AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); + if (job != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + JobsSnapshot jobsSnapshot; + try { + jobsSnapshot = autoIngestMonitor.deprioritizeJob(job); + refreshTables(jobsSnapshot); + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), job.getManifest().getFilePath()); + LOGGER.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } + setCursor(Cursor.getDefaultCursor()); + } }//GEN-LAST:event_deprioritizeJobButtonActionPerformed @Messages({"AutoIngestDashboard.errorMessage.caseDeprioritization=Failed to deprioritize case \"%s\"."}) private void deprioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeCaseButtonActionPerformed -// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) { -// setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); -// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString(); -// JobsSnapshot jobsSnapshot; -// try { -// jobsSnapshot = autoIngestMonitor.deprioritizeCase(caseName); -// refreshTables(jobsSnapshot); -// } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { -// String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), caseName); -// LOGGER.log(Level.SEVERE, errorMessage, ex); -// MessageNotifyUtil.Message.error(errorMessage); -// } -// setCursor(Cursor.getDefaultCursor()); -// } + AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); + if (job != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + String caseName = job.getManifest().getCaseName(); + JobsSnapshot jobsSnapshot; + try { + jobsSnapshot = autoIngestMonitor.deprioritizeCase(caseName); + refreshTables(jobsSnapshot); + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), caseName); + LOGGER.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } + setCursor(Cursor.getDefaultCursor()); + } }//GEN-LAST:event_deprioritizeCaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -986,34 +591,29 @@ final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JScrollPane runningScrollPane; private javax.swing.JTextField tbServicesStatusMessage; // End of variables declaration//GEN-END:variables + /** + * A task that refreshes the UI components on this panel to reflect a + * snapshot of the pending, running and completed auto ingest jobs lists of + * an auto ingest cluster. + */ + private class RefreshComponentsTask implements Runnable { -// private class AutoIngestTableModel extends DefaultTableModel { -// -// private static final long serialVersionUID = 1L; -// -// private AutoIngestTableModel(String[] headers, int i) { -// super(headers, i); -// } -// -// @Override -// public boolean isCellEditable(int row, int column) { -// return false; -// } -// -// @Override -// public Class getColumnClass(int columnIndex) { -// if (columnIndex == JobsTableModelColumns.PRIORITY.ordinal()) { -// return Integer.class; -// } else if (columnIndex == JobsTableModelColumns.CREATED_TIME.ordinal() -// || columnIndex == JobsTableModelColumns.COMPLETED_TIME.ordinal() -// || columnIndex == JobsTableModelColumns.STARTED_TIME.ordinal() -// || columnIndex == JobsTableModelColumns.STAGE_TIME.ordinal()) { -// return Date.class; -// } else if (columnIndex == JobsTableModelColumns.STATUS.ordinal()) { -// return Boolean.class; -// } else { -// return super.getColumnClass(columnIndex); -// } -// } -// } + private final JobsSnapshot jobsSnapshot; + + /** + * Constructs a task that refreshes the UI components on this panel to + * reflect a snapshot of the pending, running and completed auto ingest + * jobs lists of an auto ingest cluster. + * + * @param jobsSnapshot The jobs snapshot. + */ + RefreshComponentsTask(JobsSnapshot jobsSnapshot) { + this.jobsSnapshot = jobsSnapshot; + } + + @Override + public void run() { + refreshTables(jobsSnapshot); + } + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index e37f419802..791b487b98 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -1,11 +1,23 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.experimental.autoingest; -import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.util.ArrayList; @@ -17,9 +29,11 @@ import javax.swing.SwingWorker; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; +import org.openide.nodes.Node; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.JobNode; /** * @@ -49,22 +63,25 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa switch (type) { case PENDING_JOB: - outlineView.setPropertyColumns(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), - Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), - Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text()); + outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), + Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text()); break; case RUNNING_JOB: - outlineView.setPropertyColumns("Stage", "Stage"); + outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), + Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), + Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), + Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text()); break; case COMPLETED_JOB: - outlineView.setPropertyColumns(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), - "Date Started", "Date Started", - "Date Completed", "Date Completed", - "Status", "Status"); + outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), + Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), + Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text()); break; default: } - ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestNode_col1_text()); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestNode_caseName_text()); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); outline.setRootVisible(false); outline.setColumnSorted(0, false, 1); @@ -73,8 +90,6 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa } outline.setRowSelectionAllowed(false); - - // outlineView.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); add(outlineView, java.awt.BorderLayout.CENTER); } @@ -117,7 +132,13 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa setLayout(new java.awt.BorderLayout()); }// //GEN-END:initComponents - + AutoIngestJob getSelectedAutoIngestJob() { + Node[] selectedRows = explorerManager.getSelectedNodes(); + if (selectedRows.length == 1) { + return ((JobNode) selectedRows[0]).getAutoIngestJob(); + } + return null; + } // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java index e436ab03bc..4d01e4243d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java @@ -1,12 +1,24 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.experimental.autoingest; -import java.nio.file.Path; -import java.util.ArrayList; +import java.time.Instant; import java.util.Date; import java.util.List; import org.openide.nodes.AbstractNode; @@ -21,10 +33,15 @@ import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; final class AutoIngestNode extends AbstractNode { @Messages({ - "AutoIngestNode.col1.text=Case Name", - "AutoIngestNode.col2.text=File Name", - "AutoIngestNode.col3.text=Date Created", - "AutoIngestNode.col4.text=Priority" + "AutoIngestNode.caseName.text=Case Name", + "AutoIngestNode.dataSource.text=Data Source", + "AutoIngestNode.hostName.text=Host Name", + "AutoIngestNode.stage.text=Stage", + "AutoIngestNode.stageTime.text=Time in Stage", + "AutoIngestNode.jobCreated.text=Job Created", + "AutoIngestNode.jobCompleted.text=Job Completed", + "AutoIngestNode.priority.text=Priority", + "AutoIngestNode.status.text=Status" }) AutoIngestNode(List jobs, AutoIngestJobType type) { @@ -33,7 +50,7 @@ final class AutoIngestNode extends AbstractNode { static class AutoIngestNodeChildren extends ChildFactory { - AutoIngestJobType autoIngestJobType; + private final AutoIngestJobType autoIngestJobType; private final List jobs; AutoIngestNodeChildren(List jobList, AutoIngestJobType type) { @@ -51,7 +68,7 @@ final class AutoIngestNode extends AbstractNode { @Override protected Node createNodeForKey(AutoIngestJob key) { - return new PendingJobNode(key, autoIngestJobType); + return new JobNode(key, autoIngestJobType); } } @@ -59,26 +76,22 @@ final class AutoIngestNode extends AbstractNode { /** * A node which represents a single multi user case. */ - static final class PendingJobNode extends AbstractNode { + static final class JobNode extends AbstractNode { private final AutoIngestJob autoIngestJob; - private final String caseName; - private final Path fileName; - private final Date dateCreated; - private final int priority; private final AutoIngestJobType jobType; - PendingJobNode(AutoIngestJob job, AutoIngestJobType type) { + JobNode(AutoIngestJob job, AutoIngestJobType type) { super(Children.LEAF); jobType = type; autoIngestJob = job; - caseName = autoIngestJob.getManifest().getCaseName(); - fileName = autoIngestJob.getManifest().getDataSourcePath().getFileName(); - dateCreated = autoIngestJob.getManifest().getDateFileCreated(); - priority = autoIngestJob.getPriority(); - super.setName(caseName); - setName(caseName); - setDisplayName(caseName); + super.setName(autoIngestJob.getManifest().getCaseName()); + setName(autoIngestJob.getManifest().getCaseName()); + setDisplayName(autoIngestJob.getManifest().getCaseName()); + } + + AutoIngestJob getAutoIngestJob(){ + return autoIngestJob; } @Override @@ -89,41 +102,28 @@ final class AutoIngestNode extends AbstractNode { ss = Sheet.createPropertiesSet(); s.put(ss); } - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), caseName)); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), autoIngestJob.getManifest().getCaseName())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); switch (jobType) { - case PENDING_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), fileName.toString())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Integer.toString(priority))); + case PENDING_JOB: + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), autoIngestJob.getPriority())); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); - ss.put(new NodeProperty<>("Stage", "Stage", "Stage", status.getDescription())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(),autoIngestJob.getProcessingHostName())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), status.getDescription())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), (Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime()))); break; case COMPLETED_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); - ss.put(new NodeProperty<>("Date Started", "Date Started", "Date Started", autoIngestJob.getProcessingStageStartDate())); - ss.put(new NodeProperty<>("Date Completed - Prop6", "Date Completed", "Date Completed - Prop6", autoIngestJob.getCompletedDate())); - ss.put(new NodeProperty<>("Status", "Status", "Status", autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), autoIngestJob.getCompletedDate())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); break; default: } -// AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); - // ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), Bundle.AutoIngestNode_col1_text(), caseName)); -// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), Bundle.AutoIngestNode_col2_text(), fileName.toString())); -// ss.put(new NodeProperty<>("Host Name - Prop3", "Host Name - Prop3", "Host Name - Prop3", autoIngestJob.getProcessingHostName())); -// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), Bundle.AutoIngestNode_col3_text(), dateCreated.toString())); -// ss.put(new NodeProperty<>("Date Started - Prop5", "Date Started - Prop5", "Date Started - Prop5", autoIngestJob.getProcessingStageStartDate())); -// ss.put(new NodeProperty<>("Date Completed - Prop6", "Date Completed - Prop6", "Date Completed - Prop6", autoIngestJob.getCompletedDate())); -// ss.put(new NodeProperty<>("Stage - Prop7", "Stage - Prop7", "Stage - Prop7", status.getDescription())); -// ss.put(new NodeProperty<>("Status - Prop8", "Status - Prop8", "Status - Prop8", autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); -// ss.put(new NodeProperty<>("Stage Time - Prop9", "Stage Time - Prop9", "Stage Time - Prop9", (Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime()))); -// ss.put(new NodeProperty<>("Case Directory - Prop10", "Case Directory - Prop10", "Case Directory - Prop10", autoIngestJob.getCaseDirectoryPath())); -// ss.put(new NodeProperty<>("Manifest Path - Prop11", "Manifest Path - Prop11", "Manifest Path - Prop11", autoIngestJob.getManifest().getFilePath())); -// ss.put(new NodeProperty<>(Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Bundle.AutoIngestNode_col4_text(), Integer.toString(priority))); return s; } - } enum AutoIngestJobType { From 3d6dd20d90b138f43c2b69e255d7d85868f769bd Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 5 Apr 2018 14:11:06 -0400 Subject: [PATCH 06/64] Improved schema initialization. Added property change listener. Cleanup. --- .../HealthMonitorCaseEventListener.java | 53 +++++ .../autopsy/healthmonitor/Installer.java | 20 +- .../healthmonitor/ServicesHealthMonitor.java | 182 ++++++++++++------ 3 files changed, 177 insertions(+), 78 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java new file mode 100644 index 0000000000..5c8a6f675d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java @@ -0,0 +1,53 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.healthmonitor; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import org.sleuthkit.autopsy.casemodule.Case; + +/** + * Listener for case events + */ +final class HealthMonitorCaseEventListener implements PropertyChangeListener { + + private final ExecutorService jobProcessingExecutor; + private static final String CASE_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d"; + + HealthMonitorCaseEventListener() { + jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build()); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + + switch (Case.Events.valueOf(evt.getPropertyName())) { + + case CURRENT_CASE: + if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof Case)) { + // When a case is closed, write the current metrics to the database + jobProcessingExecutor.submit(new ServicesHealthMonitor.DatabaseWriteTask()); + } + break; + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java index b77ba067d7..5d294aca31 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java @@ -20,11 +20,13 @@ package org.sleuthkit.autopsy.healthmonitor; import java.util.logging.Level; import org.openide.modules.ModuleInstall; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; public class Installer extends ModuleInstall { private static final Logger logger = Logger.getLogger(Installer.class.getName()); + private final HealthMonitorCaseEventListener pcl = new HealthMonitorCaseEventListener(); private static final long serialVersionUID = 1L; private static Installer instance; @@ -42,25 +44,13 @@ public class Installer extends ModuleInstall { @Override public void restored() { + + Case.addPropertyChangeListener(pcl); + try { ServicesHealthMonitor.startUp(); } catch (HealthMonitorException ex) { logger.log(Level.SEVERE, "Error starting health services monitor", ex); } } - - @Override - public boolean closing() { - //platform about to close - ServicesHealthMonitor.close(); - - return true; - } - - @Override - public void uninstalled() { - //module is being unloaded - ServicesHealthMonitor.close(); - - } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index ab2510ca59..18fe6ba0ca 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -53,7 +53,7 @@ public class ServicesHealthMonitor { private final static String DATABASE_NAME = "ServicesHealthMonitor"; private final static String MODULE_NAME = "ServicesHealthMonitor"; private final static String IS_ENABLED_KEY = "is_enabled"; - private final static long DATABASE_WRITE_INTERVAL = 1; // Minutes + private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 0); @@ -75,7 +75,14 @@ public class ServicesHealthMonitor { if (ModuleSettings.settingExists(MODULE_NAME, IS_ENABLED_KEY)) { if(ModuleSettings.getConfigSetting(MODULE_NAME, IS_ENABLED_KEY).equals("true")){ isEnabled.set(true); - activateMonitor(); + try { + activateMonitor(); + } catch (HealthMonitorException ex) { + // If we failed to activate it, then disable the monitor + logger.log(Level.SEVERE, "Health monitor activation failed - disabling health monitor"); + setEnabled(false); + throw ex; + } return; } } @@ -118,12 +125,12 @@ public class ServicesHealthMonitor { if (! databaseExists()) { // If not, create a new one - System.out.println(" No database exists - setting up new one"); createDatabase(); - initializeDatabaseSchema(); } - // Any database upgrades would happen here + if( ! databaseIsInitialized()) { + initializeDatabaseSchema(); + } } finally { try { @@ -202,9 +209,11 @@ public class ServicesHealthMonitor { } if(enabled) { + getInstance().activateMonitor(); + + // If activateMonitor fails, we won't update either of these ModuleSettings.setConfigSetting(MODULE_NAME, IS_ENABLED_KEY, "true"); isEnabled.set(true); - getInstance().activateMonitor(); } else { ModuleSettings.setConfigSetting(MODULE_NAME, IS_ENABLED_KEY, "false"); isEnabled.set(false); @@ -271,14 +280,12 @@ public class ServicesHealthMonitor { } } - // TODO: Make private once testing is done /** * Write the collected metrics to the database. * @throws HealthMonitorException */ - void writeCurrentStateToDatabase() throws HealthMonitorException { - logger.log(Level.INFO, "Writing health monitor metrics to database"); - + private void writeCurrentStateToDatabase() throws HealthMonitorException { + Map timingMapCopy; // Do as little as possible within the synchronized block since it will @@ -293,20 +300,13 @@ public class ServicesHealthMonitor { timingMapCopy = new HashMap<>(timingInfoMap); timingInfoMap.clear(); } + logger.log(Level.INFO, "Writing health monitor metrics to database"); // Check if there's anything to report (right now we only have the timing map) if(timingMapCopy.keySet().isEmpty()) { return; } - // TODO: Debug - for(String name:timingMapCopy.keySet()){ - TimingInfo info = timingMapCopy.get(name); - long timestamp = System.currentTimeMillis(); - System.out.println(" Name: " + name + "\tTimestamp: " + timestamp + "\tAverage: " + info.getAverage() + - "\tMax: " + info.getMax() + "\tMin: " + info.getMin()); - } - // Write to the database CoordinationService.Lock lock = getSharedDbLock(); if(lock == null) { @@ -354,11 +354,6 @@ public class ServicesHealthMonitor { } } - // TODO: debug - synchronized void clearCurrentState() { - timingInfoMap.clear(); - } - /** * Call during application closing - attempts to log any remaining entries. */ @@ -388,23 +383,13 @@ public class ServicesHealthMonitor { } } - // TODO: debug - synchronized void printCurrentState() { - System.out.println("\nTiming Info Map:"); - for(String name:timingInfoMap.keySet()) { - System.out.print(name + "\t"); - timingInfoMap.get(name).print(); - } - } - - // TODO: Change to private after testing /** * Check whether the health monitor database exists. * Does not check the schema. * @return true if the database exists, false otherwise * @throws HealthMonitorException */ - boolean databaseExists() throws HealthMonitorException { + private boolean databaseExists() throws HealthMonitorException { try { // Use the same database settings as the case CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); @@ -449,26 +434,6 @@ public class ServicesHealthMonitor { throw new HealthMonitorException("Failed to delete health monitor database", ex); } } - - // TODO: At least make private - /** - * Delete the current health monitor database (for testing only) - * Make private after test - */ - void deleteDatabase() { - try { - // Use the same database settings as the case - CaseDbConnectionInfo db = UserPreferences.getDatabaseConnectionInfo(); - Class.forName("org.postgresql.Driver"); //NON-NLS - try (Connection connection = DriverManager.getConnection("jdbc:postgresql://" + db.getHost() + ":" + db.getPort() + "/postgres", db.getUserName(), db.getPassword()); //NON-NLS - Statement statement = connection.createStatement();) { - String deleteCommand = "DROP DATABASE \"" + DATABASE_NAME + "\""; //NON-NLS - statement.execute(deleteCommand); - } - } catch (UserPreferencesException | ClassNotFoundException | SQLException ex) { - logger.log(Level.SEVERE, "Failed to delete health monitor database", ex); - } - } /** * Setup a connection pool for db connections. @@ -494,7 +459,7 @@ public class ServicesHealthMonitor { connectionPool.setPassword(db.getPassword()); // tweak pool configuration - connectionPool.setInitialSize(2); // start with 2 connections + connectionPool.setInitialSize(3); // start with 3 connections connectionPool.setMaxIdle(CONN_POOL_SIZE); // max of 10 idle connections connectionPool.setValidationQuery("SELECT version()"); } catch (UserPreferencesException ex) { @@ -539,6 +504,95 @@ public class ServicesHealthMonitor { } } + /** + * Test whether the database schema has been initialized. + * We do this by looking for the version number. + * @return True if it has been initialized, false otherwise. + * @throws HealthMonitorException + */ + private boolean databaseIsInitialized() throws HealthMonitorException { + Connection conn = connect(); + if(conn == null) { + throw new HealthMonitorException("Error getting database connection"); + } + ResultSet resultSet = null; + + try (Statement statement = conn.createStatement()) { + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_VERSION'"); + return resultSet.next(); + } catch (SQLException ex) { + // This likely just means that the db_info table does not exist + return false; + } finally { + if(resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing result set", ex); + } + } + try { + conn.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing Connection.", ex); + } + } + } + + /** + * Get the current schema version + * @return the current schema version + * @throws HealthMonitorException + */ + private CaseDbSchemaVersionNumber getVersion() throws HealthMonitorException { + Connection conn = connect(); + if(conn == null) { + throw new HealthMonitorException("Error getting database connection"); + } + ResultSet resultSet = null; + + try (Statement statement = conn.createStatement()) { + int minorVersion = 0; + int majorVersion = 0; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'"); + if (resultSet.next()) { + String minorVersionStr = resultSet.getString("value"); + try { + minorVersion = Integer.parseInt(minorVersionStr); + } catch (NumberFormatException ex) { + throw new HealthMonitorException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt"); + } + } + + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_VERSION'"); + if (resultSet.next()) { + String majorVersionStr = resultSet.getString("value"); + try { + majorVersion = Integer.parseInt(majorVersionStr); + } catch (NumberFormatException ex) { + throw new HealthMonitorException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt"); + } + } + + return new CaseDbSchemaVersionNumber(majorVersion, minorVersion); + } catch (SQLException ex) { + throw new HealthMonitorException("Error initializing database", ex); + } finally { + if(resultSet != null) { + try { + resultSet.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing result set", ex); + } + } + try { + conn.close(); + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error closing Connection.", ex); + } + } + } + /** * Initialize the database. * @throws HealthMonitorException @@ -549,8 +603,9 @@ public class ServicesHealthMonitor { throw new HealthMonitorException("Error getting database connection"); } - // TODO: transaction try (Statement statement = conn.createStatement()) { + conn.setAutoCommit(false); + StringBuilder createTimingTable = new StringBuilder(); createTimingTable.append("CREATE TABLE IF NOT EXISTS timing_data ("); createTimingTable.append("id SERIAL PRIMARY KEY,"); @@ -574,13 +629,19 @@ public class ServicesHealthMonitor { statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); + conn.commit(); } catch (SQLException ex) { + try { + conn.rollback(); + } catch (SQLException ex2) { + logger.log(Level.SEVERE, "Rollback error"); + } throw new HealthMonitorException("Error initializing database", ex); } finally { try { conn.close(); } catch (SQLException ex) { - logger.log(Level.SEVERE, "Error closing Connection.", ex); + logger.log(Level.SEVERE, "Error closing connection.", ex); } } } @@ -589,7 +650,7 @@ public class ServicesHealthMonitor { * The task called by the ScheduledThreadPoolExecutor to handle * the database writes. */ - private final class DatabaseWriteTask implements Runnable { + static final class DatabaseWriteTask implements Runnable { /** * Write current metric data to the database @@ -720,10 +781,5 @@ public class ServicesHealthMonitor { long getCount() { return count; } - - // TODO: debug - void print() { - System.out.println("count: " + count + "\tsum: " + sum + "\tmax: " + max + "\tmin: " + min); - } } } From f21feb0d3afe606941c30b848e92f19182f34137 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 5 Apr 2018 14:15:02 -0400 Subject: [PATCH 07/64] Modified metric names. --- .../src/org/sleuthkit/autopsy/keywordsearch/Ingester.java | 2 +- .../src/org/sleuthkit/autopsy/keywordsearch/Server.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index 679a646995..f956513eca 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -237,7 +237,7 @@ class Ingester { try { //TODO: consider timeout thread, or vary socket timeout based on size of indexed content - TimingMetric metric = ServicesHealthMonitor.getTimingMetric("solr index chunk"); + TimingMetric metric = ServicesHealthMonitor.getTimingMetric("Solr: Index chunk"); solrServer.addDocument(updateDoc); ServicesHealthMonitor.submitTimingMetric(metric); uncommitedIngests = true; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 3b4e494480..5748524ada 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -775,7 +775,7 @@ public class Server { IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory()); currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS } - TimingMetric metric = ServicesHealthMonitor.getTimingMetric("solr connectivity check"); + TimingMetric metric = ServicesHealthMonitor.getTimingMetric("Solr: Connectivity check"); connectToSolrServer(currentSolrServer); ServicesHealthMonitor.submitTimingMetric(metric); From fc53bff61aeaff82b2d29817111104c52777dbd3 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 5 Apr 2018 14:17:43 -0400 Subject: [PATCH 08/64] Remove unused method --- .../healthmonitor/ServicesHealthMonitor.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index 18fe6ba0ca..ebed5d5f61 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -354,35 +354,6 @@ public class ServicesHealthMonitor { } } - /** - * Call during application closing - attempts to log any remaining entries. - */ - static synchronized void close() { - if(isEnabled.get()) { - - // Stop the timer - try { - getInstance().stopTimer(); - } catch (HealthMonitorException ex) { - logger.log(Level.SEVERE, "Error shutting down timer", ex); - } - - // Write current data - try { - getInstance().writeCurrentStateToDatabase(); - } catch (HealthMonitorException ex) { - logger.log(Level.SEVERE, "Error writing final metric data to database", ex); - } - - // Shutdown connection pool - try { - getInstance().shutdownConnections(); - } catch (HealthMonitorException ex) { - logger.log(Level.SEVERE, "Error shutting down connection pool", ex); - } - } - } - /** * Check whether the health monitor database exists. * Does not check the schema. From 9cdc521379319a344d47e4caf42761c3f651f990 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 5 Apr 2018 14:57:48 -0400 Subject: [PATCH 09/64] 3610 display stage time as human readable string again --- .../guiutils/DurationCellRenderer.java | 56 ++++++++++--------- .../autoingest/AutoIngestNode.java | 39 ++++++++----- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java index 6aab063952..5e8dfbcdea 100644 --- a/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.guiutils; -import java.awt.Color; import java.awt.Component; import java.time.Duration; import javax.swing.JTable; @@ -41,36 +40,39 @@ public class DurationCellRenderer extends GrayableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof Long) { { - Duration d = Duration.ofMillis((long) value); - if (d.isNegative()) { - d = Duration.ofMillis(-(long) value); - } - - String result; - long days = d.toDays(); - long hours = d.minusDays(days).toHours(); - long minutes = d.minusDays(days).minusHours(hours).toMinutes(); - long seconds = d.minusDays(days).minusHours(hours).minusMinutes(minutes).getSeconds(); - - if (minutes > 0) { - if (hours > 0) { - if (days > 0) { - result = days + " d " + hours + " h " + minutes + " m " + seconds + " s"; - } else { - result = hours + " h " + minutes + " m " + seconds + " s"; - } - } else { - result = minutes + " m " + seconds + " s"; - } - } else { - result = seconds + " s"; - } - - setText(result); + setText(DurationCellRenderer.longToDurationString((long)value)); } } grayCellIfTableNotEnabled(table, isSelected); return this; } + public static String longToDurationString(long duration) { + Duration d = Duration.ofMillis(duration); + if (d.isNegative()) { + d = Duration.ofMillis(-duration); + } + + String result; + long days = d.toDays(); + long hours = d.minusDays(days).toHours(); + long minutes = d.minusDays(days).minusHours(hours).toMinutes(); + long seconds = d.minusDays(days).minusHours(hours).minusMinutes(minutes).getSeconds(); + + if (minutes > 0) { + if (hours > 0) { + if (days > 0) { + result = days + " d " + hours + " h " + minutes + " m " + seconds + " s"; + } else { + result = hours + " h " + minutes + " m " + seconds + " s"; + } + } else { + result = minutes + " m " + seconds + " s"; + } + } else { + result = seconds + " s"; + } + return result; + } + } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java index 4d01e4243d..4169eaca09 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java @@ -28,6 +28,7 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; final class AutoIngestNode extends AbstractNode { @@ -41,7 +42,7 @@ final class AutoIngestNode extends AbstractNode { "AutoIngestNode.jobCreated.text=Job Created", "AutoIngestNode.jobCompleted.text=Job Completed", "AutoIngestNode.priority.text=Priority", - "AutoIngestNode.status.text=Status" + "AutoIngestNode.status.text=Status" }) AutoIngestNode(List jobs, AutoIngestJobType type) { @@ -89,8 +90,8 @@ final class AutoIngestNode extends AbstractNode { setName(autoIngestJob.getManifest().getCaseName()); setDisplayName(autoIngestJob.getManifest().getCaseName()); } - - AutoIngestJob getAutoIngestJob(){ + + AutoIngestJob getAutoIngestJob() { return autoIngestJob; } @@ -102,23 +103,33 @@ final class AutoIngestNode extends AbstractNode { ss = Sheet.createPropertiesSet(); s.put(ss); } - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), autoIngestJob.getManifest().getCaseName())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), + autoIngestJob.getManifest().getCaseName())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), + autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); switch (jobType) { - case PENDING_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), autoIngestJob.getPriority())); + case PENDING_JOB: + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + autoIngestJob.getManifest().getDateFileCreated())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), + autoIngestJob.getPriority())); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(),autoIngestJob.getProcessingHostName())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), status.getDescription())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), (Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime()))); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), + autoIngestJob.getProcessingHostName())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), + status.getDescription())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), + DurationCellRenderer.longToDurationString((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())))); break; case COMPLETED_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), autoIngestJob.getCompletedDate())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + autoIngestJob.getManifest().getDateFileCreated())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), + autoIngestJob.getCompletedDate())); + ss.put(new NodeProperty<>(Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), + autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); break; default: } From d5f1064e8855b7523e5e63a16dfeb5d11aa3e6a4 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 6 Apr 2018 13:55:49 -0400 Subject: [PATCH 10/64] Added host name to timing metric --- .../healthmonitor/ServicesHealthMonitor.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index ebed5d5f61..d628f2e8b9 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -301,6 +301,15 @@ public class ServicesHealthMonitor { timingInfoMap.clear(); } logger.log(Level.INFO, "Writing health monitor metrics to database"); + + String hostName; + try { + hostName = java.net.InetAddress.getLocalHost().getHostName(); + } catch (java.net.UnknownHostException ex) { + // Write it to the database but log a warning + logger.log(Level.WARNING, "Unable to look up host name"); + hostName = "unknown"; + } // Check if there's anything to report (right now we only have the timing map) if(timingMapCopy.keySet().isEmpty()) { @@ -320,18 +329,19 @@ public class ServicesHealthMonitor { } // Add timing metrics to the database - String addTimingInfoSql = "INSERT INTO timing_data (name, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?)"; + String addTimingInfoSql = "INSERT INTO timing_data (name, host, timestamp, count, average, max, min) VALUES (?, ?, ?, ?, ?, ?, ?)"; try (PreparedStatement statement = conn.prepareStatement(addTimingInfoSql)) { for(String name:timingMapCopy.keySet()) { TimingInfo info = timingMapCopy.get(name); statement.setString(1, name); - statement.setLong(2, System.currentTimeMillis()); - statement.setLong(3, info.getCount()); - statement.setLong(4, info.getAverage()); - statement.setLong(5, info.getMax()); - statement.setLong(6, info.getMin()); + statement.setString(2, hostName); + statement.setLong(3, System.currentTimeMillis()); + statement.setLong(4, info.getCount()); + statement.setLong(5, info.getAverage()); + statement.setLong(6, info.getMax()); + statement.setLong(7, info.getMin()); statement.execute(); } @@ -581,6 +591,7 @@ public class ServicesHealthMonitor { createTimingTable.append("CREATE TABLE IF NOT EXISTS timing_data ("); createTimingTable.append("id SERIAL PRIMARY KEY,"); createTimingTable.append("name text NOT NULL,"); + createTimingTable.append("host text NOT NULL,"); createTimingTable.append("timestamp bigint NOT NULL,"); createTimingTable.append("count bigint NOT NULL,"); createTimingTable.append("average bigint NOT NULL,"); From 3f20808ed4f3be6870d69d84aee2721d03562f48 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 6 Apr 2018 14:48:52 -0400 Subject: [PATCH 11/64] 3610 refresh no longer causes table contents to blink with asynchronous= false --- .../autoingest/AutoIngestDashboard.java | 4 +- .../autoingest/AutoIngestJobsPanel.java | 72 +++---------------- .../autoingest/AutoIngestNode.java | 28 ++++++-- 3 files changed, 35 insertions(+), 69 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 43d0d791d4..4fb2e1e989 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -268,7 +268,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Override public void update(Observable observable, Object arg) { - EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); + EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); } /** @@ -282,7 +282,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { runningJobsPanel.refresh(jobsSnapshot); finishedJobsPanel.refresh(jobsSnapshot); } - + /** * Exception type thrown when there is an error completing an auto ingest * dashboard operation. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 791b487b98..3bb22237c5 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -20,17 +20,12 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Dimension; import java.awt.EventQueue; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; -import javax.swing.SwingWorker; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.JobNode; @@ -45,7 +40,6 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; - private JobListWorker jobListWorker; private final AutoIngestJobType type; /** @@ -65,7 +59,8 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa case PENDING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), - Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text()); + Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), + "Time Since Created", "Time Since Created"); break; case RUNNING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), @@ -91,7 +86,8 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa } outline.setRowSelectionAllowed(false); add(outlineView, java.awt.BorderLayout.CENTER); - + EmptyNode emptyNode = new EmptyNode("Please wait..."); + explorerManager.setRootContext(emptyNode); } @Override @@ -111,12 +107,13 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa } void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { - if (jobListWorker == null || jobListWorker.isDone()) { + synchronized (this) { outline.setRowSelectionAllowed(false); -// EmptyNode emptyNode = new EmptyNode("Refreshing..."); -// explorerManager.setRootContext(emptyNode); - jobListWorker = new JobListWorker(jobsSnapshot, type); - jobListWorker.execute(); + EventQueue.invokeLater(() -> { + AutoIngestNode autoIngestNode = new AutoIngestNode(jobsSnapshot, type); + explorerManager.setRootContext(autoIngestNode); + outline.setRowSelectionAllowed(true); + }); } } @@ -141,54 +138,5 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa } // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables - /** - * Swingworker to fetch the updated List of cases in a background thread - */ - private class JobListWorker extends SwingWorker, Void> { - - private final AutoIngestMonitor.JobsSnapshot jobsSnapshot; - private final AutoIngestJobType jobType; - - JobListWorker(AutoIngestMonitor.JobsSnapshot snapshot, AutoIngestJobType type) { - jobsSnapshot = snapshot; - jobType = type; - } - - @Override - protected List doInBackground() throws Exception { - List jobs; - switch (jobType) { - case PENDING_JOB: - jobs = jobsSnapshot.getPendingJobs(); - break; - case RUNNING_JOB: - jobs = jobsSnapshot.getRunningJobs(); - break; - case COMPLETED_JOB: - jobs = jobsSnapshot.getCompletedJobs(); - break; - default: - jobs = new ArrayList<>(); - - } - jobs.sort(new AutoIngestJob.PriorityComparator()); - return jobs; - } - - @Override - protected void done() { - try { - List jobs = get(); - EventQueue.invokeLater(() -> { - AutoIngestNode autoIngestNode = new AutoIngestNode(jobs, jobType); - explorerManager.setRootContext(autoIngestNode); - outline.setRowSelectionAllowed(true); - }); - } catch (InterruptedException | ExecutionException ex) { - Exceptions.printStackTrace(ex); - } - - } - } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java index 4169eaca09..869da413c2 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.time.Instant; +import java.util.ArrayList; import java.util.Date; import java.util.List; import org.openide.nodes.AbstractNode; @@ -28,6 +29,7 @@ import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; @@ -45,22 +47,36 @@ final class AutoIngestNode extends AbstractNode { "AutoIngestNode.status.text=Status" }) - AutoIngestNode(List jobs, AutoIngestJobType type) { - super(Children.create(new AutoIngestNodeChildren(jobs, type), true)); + AutoIngestNode(JobsSnapshot snapshot, AutoIngestJobType type) { + super(Children.create(new AutoIngestNodeChildren(snapshot, type), false)); } static class AutoIngestNodeChildren extends ChildFactory { private final AutoIngestJobType autoIngestJobType; - private final List jobs; + private final JobsSnapshot jobsSnapshot; - AutoIngestNodeChildren(List jobList, AutoIngestJobType type) { - this.jobs = jobList; + AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobType type) { + jobsSnapshot = snapshot; autoIngestJobType = type; } @Override protected boolean createKeys(List list) { + List jobs; + switch (autoIngestJobType) { + case PENDING_JOB: + jobs = jobsSnapshot.getPendingJobs(); + break; + case RUNNING_JOB: + jobs = jobsSnapshot.getRunningJobs(); + break; + case COMPLETED_JOB: + jobs = jobsSnapshot.getCompletedJobs(); + break; + default: + jobs = new ArrayList<>(); + } if (jobs != null && jobs.size() > 0) { list.addAll(jobs); } @@ -113,6 +129,8 @@ final class AutoIngestNode extends AbstractNode { autoIngestJob.getManifest().getDateFileCreated())); ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), autoIngestJob.getPriority())); + ss.put(new NodeProperty<>("Time Since Created", "Time Since Created", "Time Since Created", + DurationCellRenderer.longToDurationString((Date.from(Instant.now()).getTime()) - (autoIngestJob.getManifest().getDateFileCreated().getTime())))); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); From 4a2b4197b27ef494cb697dab83f7626386f617f3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 9 Apr 2018 13:38:06 -0400 Subject: [PATCH 12/64] 3610 row selection, resize, icons --- .../autoingest/AutoIngestDashboard.form | 65 ++++++++-------- .../autoingest/AutoIngestDashboard.java | 76 +++++++------------ .../autoingest/AutoIngestJobsPanel.java | 44 ++++++++--- .../autoingest/AutoIngestNode.java | 2 - 4 files changed, 92 insertions(+), 95 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 68a1bb656d..0bdc79f34f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -26,36 +26,31 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -65,24 +60,24 @@ - + - + - - + + - - + + - - - + + + @@ -91,7 +86,7 @@ - + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 4fb2e1e989..d0923b63ba 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -33,6 +33,7 @@ import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; +import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; @@ -46,29 +47,6 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnaps final class AutoIngestDashboard extends JPanel implements Observer { private static final long serialVersionUID = 1L; - private static final int GENERIC_COL_MIN_WIDTH = 30; - private static final int GENERIC_COL_MAX_WIDTH = 2000; - private static final int PENDING_TABLE_COL_PREFERRED_WIDTH = 280; - private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175; - private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60; - private static final int PRIORITY_COLUMN_MAX_WIDTH = 150; - private static final int STAGE_TIME_COL_MIN_WIDTH = 250; - private static final int STAGE_TIME_COL_MAX_WIDTH = 450; - private static final int TIME_COL_MIN_WIDTH = 30; - private static final int TIME_COL_MAX_WIDTH = 250; - private static final int TIME_COL_PREFERRED_WIDTH = 140; - private static final int NAME_COL_MIN_WIDTH = 100; - private static final int NAME_COL_MAX_WIDTH = 250; - private static final int NAME_COL_PREFERRED_WIDTH = 140; - private static final int STAGE_COL_MIN_WIDTH = 70; - private static final int STAGE_COL_MAX_WIDTH = 2000; - private static final int STAGE_COL_PREFERRED_WIDTH = 300; - private static final int STATUS_COL_MIN_WIDTH = 55; - private static final int STATUS_COL_MAX_WIDTH = 250; - private static final int STATUS_COL_PREFERRED_WIDTH = 55; - private static final int COMPLETED_TIME_COL_MIN_WIDTH = 30; - private static final int COMPLETED_TIME_COL_MAX_WIDTH = 2000; - private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280; private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboard.class.getName()); private AutoIngestMonitor autoIngestMonitor; private AutoIngestJobsPanel pendingJobsPanel; @@ -155,6 +133,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { /* * Must set this flag, otherwise pop up menus don't close properly. */ + UIManager.put("PopupMenu.consumeEventOnClose", false); } @@ -278,9 +257,11 @@ final class AutoIngestDashboard extends JPanel implements Observer { * @param jobsSnapshot The jobs snapshot. */ private void refreshTables(JobsSnapshot jobsSnapshot) { +// Node[] selectedPending = pendingJobsPanel.getSelectedNodes(); pendingJobsPanel.refresh(jobsSnapshot); - runningJobsPanel.refresh(jobsSnapshot); - finishedJobsPanel.refresh(jobsSnapshot); +// pendingJobsPanel.setSelectedNodes(selectedPending); +// runningJobsPanel.refresh(jobsSnapshot); +// finishedJobsPanel.refresh(jobsSnapshot); } /** @@ -425,27 +406,24 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deprioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deprioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(clusterMetricsButton)) - .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(lbServicesStatus) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, Short.MAX_VALUE))) + .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deprioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deprioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(clusterMetricsButton)) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(lbServicesStatus) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE))) .addContainerGap()) ); @@ -461,15 +439,15 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lbPending, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(1, 1, 1) - .addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pendingScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(lbRunning) .addGap(1, 1, 1) - .addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(runningScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(lbCompleted) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(completedScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 179, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(refreshButton) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 3bb22237c5..ba3b379023 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -20,12 +20,16 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Dimension; import java.awt.EventQueue; +import java.beans.PropertyVetoException; +import java.util.Enumeration; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; +import javax.swing.table.TableColumn; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.JobNode; @@ -59,27 +63,32 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa case PENDING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), - Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), - "Time Since Created", "Time Since Created"); + Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text()); + outline.setColumnSorted(3, false, 1); + outline.setColumnSorted(0, true, 2); break; case RUNNING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text()); + outline.setColumnSorted(0, true, 1); break; case COMPLETED_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text()); + outline.setColumnSorted(3, false, 1); break; default: } ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestNode_caseName_text()); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); outline.setRootVisible(false); - outline.setColumnSorted(0, false, 1); + + outline.getColumnModel().getColumn(0).setPreferredWidth(160); + outline.getColumnModel().getColumn(1).setPreferredWidth(260); if (null == explorerManager) { explorerManager = new ExplorerManager(); @@ -108,12 +117,29 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { synchronized (this) { - outline.setRowSelectionAllowed(false); + // outline.setRowSelectionAllowed(false); + Node[] selectedNodes = explorerManager.getSelectedNodes(); + AutoIngestNode autoIngestNode = new AutoIngestNode(jobsSnapshot, type); + explorerManager.setRootContext(autoIngestNode); + outline.setRowSelectionAllowed(true); EventQueue.invokeLater(() -> { - AutoIngestNode autoIngestNode = new AutoIngestNode(jobsSnapshot, type); - explorerManager.setRootContext(autoIngestNode); - outline.setRowSelectionAllowed(true); - }); + setSelectedNodes(selectedNodes); + System.out.println("SUCESS: " + selectedNodes.length); + + }); + } + } + + Node[] getSelectedNodes() { + return explorerManager.getSelectedNodes(); + } + + void setSelectedNodes(Node[] selectedRows) { + try { + explorerManager.setSelectedNodes(selectedRows); + } catch (PropertyVetoException ignore) { + System.out.println("Unable to set selected Rows: " + ignore.toString()); + //Unable to select previously selected node } } @@ -130,7 +156,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa }// //GEN-END:initComponents AutoIngestJob getSelectedAutoIngestJob() { - Node[] selectedRows = explorerManager.getSelectedNodes(); + Node[] selectedRows = getSelectedNodes(); if (selectedRows.length == 1) { return ((JobNode) selectedRows[0]).getAutoIngestJob(); } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java index 869da413c2..e6a4d19440 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java @@ -129,8 +129,6 @@ final class AutoIngestNode extends AbstractNode { autoIngestJob.getManifest().getDateFileCreated())); ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), autoIngestJob.getPriority())); - ss.put(new NodeProperty<>("Time Since Created", "Time Since Created", "Time Since Created", - DurationCellRenderer.longToDurationString((Date.from(Instant.now()).getTime()) - (autoIngestJob.getManifest().getDateFileCreated().getTime())))); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); From 1a437d8686376ce710cca77d93876a0cec64a7d0 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Mon, 9 Apr 2018 13:50:49 -0400 Subject: [PATCH 13/64] Cleanup addressing PR review comments. --- .../HealthMonitorCaseEventListener.java | 8 +- .../healthmonitor/ServicesHealthMonitor.java | 74 +++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java index 5c8a6f675d..f6c5583692 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java @@ -30,11 +30,11 @@ import org.sleuthkit.autopsy.casemodule.Case; */ final class HealthMonitorCaseEventListener implements PropertyChangeListener { - private final ExecutorService jobProcessingExecutor; - private static final String CASE_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d"; + private final ExecutorService healthMonitorExecutor; + private static final String HEALTH_MONITOR_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d"; HealthMonitorCaseEventListener() { - jobProcessingExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(CASE_EVENT_THREAD_NAME).build()); + healthMonitorExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(HEALTH_MONITOR_EVENT_THREAD_NAME).build()); } @Override @@ -45,7 +45,7 @@ final class HealthMonitorCaseEventListener implements PropertyChangeListener { case CURRENT_CASE: if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof Case)) { // When a case is closed, write the current metrics to the database - jobProcessingExecutor.submit(new ServicesHealthMonitor.DatabaseWriteTask()); + healthMonitorExecutor.submit(new ServicesHealthMonitor.DatabaseWriteTask()); } break; } diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index d628f2e8b9..c73fa55106 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -60,10 +60,11 @@ public class ServicesHealthMonitor { private static final AtomicBoolean isEnabled = new AtomicBoolean(false); private static ServicesHealthMonitor instance; - private ScheduledThreadPoolExecutor periodicTasksExecutor; + private ScheduledThreadPoolExecutor healthMonitorOutputTimer; private final Map timingInfoMap; private static final int CONN_POOL_SIZE = 10; private BasicDataSource connectionPool = null; + private String hostName; private ServicesHealthMonitor() throws HealthMonitorException { @@ -71,6 +72,15 @@ public class ServicesHealthMonitor { // of whether the monitor is enabled. timingInfoMap = new HashMap<>(); + // Get the host name + try { + hostName = java.net.InetAddress.getLocalHost().getHostName(); + } catch (java.net.UnknownHostException ex) { + // Continue on but log a warning + logger.log(Level.WARNING, "Unable to look up host name"); + hostName = "unknown"; + } + // Read from module settings to determine if the module is enabled if (ModuleSettings.settingExists(MODULE_NAME, IS_ENABLED_KEY)) { if(ModuleSettings.getConfigSetting(MODULE_NAME, IS_ENABLED_KEY).equals("true")){ @@ -172,20 +182,20 @@ public class ServicesHealthMonitor { * Start the ScheduledThreadPoolExecutor that will handle the database writes. */ private synchronized void startTimer() { - if(periodicTasksExecutor != null) { + if(healthMonitorOutputTimer != null) { // Make sure the previous executor (if it exists) has been stopped - periodicTasksExecutor.shutdown(); + healthMonitorOutputTimer.shutdown(); } - periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build()); - periodicTasksExecutor.scheduleWithFixedDelay(new DatabaseWriteTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES); + healthMonitorOutputTimer = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build()); + healthMonitorOutputTimer.scheduleWithFixedDelay(new DatabaseWriteTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES); } /** * Stop the ScheduledThreadPoolExecutor to prevent further database writes. */ private synchronized void stopTimer() { - if(periodicTasksExecutor != null) { - periodicTasksExecutor.shutdown(); + if(healthMonitorOutputTimer != null) { + healthMonitorOutputTimer.shutdown(); } } @@ -301,15 +311,6 @@ public class ServicesHealthMonitor { timingInfoMap.clear(); } logger.log(Level.INFO, "Writing health monitor metrics to database"); - - String hostName; - try { - hostName = java.net.InetAddress.getLocalHost().getHostName(); - } catch (java.net.UnknownHostException ex) { - // Write it to the database but log a warning - logger.log(Level.WARNING, "Unable to look up host name"); - hostName = "unknown"; - } // Check if there's anything to report (right now we only have the timing map) if(timingMapCopy.keySet().isEmpty()) { @@ -587,26 +588,26 @@ public class ServicesHealthMonitor { try (Statement statement = conn.createStatement()) { conn.setAutoCommit(false); - StringBuilder createTimingTable = new StringBuilder(); - createTimingTable.append("CREATE TABLE IF NOT EXISTS timing_data ("); - createTimingTable.append("id SERIAL PRIMARY KEY,"); - createTimingTable.append("name text NOT NULL,"); - createTimingTable.append("host text NOT NULL,"); - createTimingTable.append("timestamp bigint NOT NULL,"); - createTimingTable.append("count bigint NOT NULL,"); - createTimingTable.append("average bigint NOT NULL,"); - createTimingTable.append("max bigint NOT NULL,"); - createTimingTable.append("min bigint NOT NULL"); - createTimingTable.append(")"); - statement.execute(createTimingTable.toString()); + String createTimingTable = + "CREATE TABLE IF NOT EXISTS timing_data (" + + "id SERIAL PRIMARY KEY," + + "name text NOT NULL," + + "host text NOT NULL," + + "timestamp bigint NOT NULL," + + "count bigint NOT NULL," + + "average bigint NOT NULL," + + "max bigint NOT NULL," + + "min bigint NOT NULL" + + ")"; + statement.execute(createTimingTable); - StringBuilder createDbInfoTable = new StringBuilder(); - createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info ("); - createDbInfoTable.append("id SERIAL PRIMARY KEY NOT NULL,"); - createDbInfoTable.append("name text NOT NULL,"); - createDbInfoTable.append("value text NOT NULL"); - createDbInfoTable.append(")"); - statement.execute(createDbInfoTable.toString()); + String createDbInfoTable = + "CREATE TABLE IF NOT EXISTS db_info (" + + "id SERIAL PRIMARY KEY NOT NULL," + + "name text NOT NULL," + + "value text NOT NULL" + + ")"; + statement.execute(createDbInfoTable); statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); @@ -655,8 +656,7 @@ public class ServicesHealthMonitor { */ private CoordinationService.Lock getExclusiveDbLock() throws HealthMonitorException{ try { - String databaseNodeName = DATABASE_NAME; - CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.HEALTH_MONITOR, databaseNodeName, 5, TimeUnit.MINUTES); + CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.HEALTH_MONITOR, DATABASE_NAME, 5, TimeUnit.MINUTES); if(lock != null){ return lock; From 08298e5dcec87bc66626e9939cbcd56841da0ff2 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 9 Apr 2018 16:14:32 -0400 Subject: [PATCH 14/64] 3610 retain selection through refreshes of explorer view for aid 2.0 --- .../autoingest/AutoIngestDashboard.java | 6 ++---- .../autoingest/AutoIngestJobsPanel.java | 14 ++++---------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index d0923b63ba..c3347adb32 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -257,11 +257,9 @@ final class AutoIngestDashboard extends JPanel implements Observer { * @param jobsSnapshot The jobs snapshot. */ private void refreshTables(JobsSnapshot jobsSnapshot) { -// Node[] selectedPending = pendingJobsPanel.getSelectedNodes(); pendingJobsPanel.refresh(jobsSnapshot); -// pendingJobsPanel.setSelectedNodes(selectedPending); -// runningJobsPanel.refresh(jobsSnapshot); -// finishedJobsPanel.refresh(jobsSnapshot); + runningJobsPanel.refresh(jobsSnapshot); + finishedJobsPanel.refresh(jobsSnapshot); } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index ba3b379023..ad8a92f97d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -19,17 +19,13 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Dimension; -import java.awt.EventQueue; import java.beans.PropertyVetoException; -import java.util.Enumeration; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionListener; -import javax.swing.table.TableColumn; import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.JobNode; @@ -117,16 +113,14 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { synchronized (this) { - // outline.setRowSelectionAllowed(false); + outline.setRowSelectionAllowed(false); Node[] selectedNodes = explorerManager.getSelectedNodes(); AutoIngestNode autoIngestNode = new AutoIngestNode(jobsSnapshot, type); explorerManager.setRootContext(autoIngestNode); outline.setRowSelectionAllowed(true); - EventQueue.invokeLater(() -> { - setSelectedNodes(selectedNodes); - System.out.println("SUCESS: " + selectedNodes.length); - - }); + if (selectedNodes.length > 0) { + setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())}); + } } } From 8d7cc2550fabef3a8a9f75d4cfddd4cd4eea0b72 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 9 Apr 2018 16:36:18 -0400 Subject: [PATCH 15/64] 3610 some clean up of various auto ingest outline view changes --- .../guiutils/DurationCellRenderer.java | 12 ++++++-- .../autoingest/AutoIngestDashboard.java | 28 +++++++++++-------- .../autoingest/AutoIngestJobsPanel.java | 20 ++++--------- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java index 5e8dfbcdea..9ab4ec281b 100644 --- a/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java +++ b/Core/src/org/sleuthkit/autopsy/guiutils/DurationCellRenderer.java @@ -40,13 +40,21 @@ public class DurationCellRenderer extends GrayableCellRenderer { public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (value instanceof Long) { { - setText(DurationCellRenderer.longToDurationString((long)value)); + setText(DurationCellRenderer.longToDurationString((long) value)); } } grayCellIfTableNotEnabled(table, isSelected); return this; } + /** + * Convert a duration represented by a long to a human readable string with + * with days, hours, minutes, and seconds components. + * + * @param duration - the representation of the duration in long form + * + * @return - the representation of the duration in String form. + */ public static String longToDurationString(long duration) { Duration d = Duration.ofMillis(duration); if (d.isNegative()) { @@ -58,7 +66,7 @@ public class DurationCellRenderer extends GrayableCellRenderer { long hours = d.minusDays(days).toHours(); long minutes = d.minusDays(days).minusHours(hours).toMinutes(); long seconds = d.minusDays(days).minusHours(hours).minusMinutes(minutes).getSeconds(); - + if (minutes > 0) { if (hours > 0) { if (days > 0) { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index c3347adb32..3d4a78f1ff 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -33,7 +33,6 @@ import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; -import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; @@ -51,7 +50,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { private AutoIngestMonitor autoIngestMonitor; private AutoIngestJobsPanel pendingJobsPanel; private AutoIngestJobsPanel runningJobsPanel; - private AutoIngestJobsPanel finishedJobsPanel; + private AutoIngestJobsPanel completedJobsPanel; /** * Maintain a mapping of each service to it's last status update. @@ -79,6 +78,10 @@ final class AutoIngestDashboard extends JPanel implements Observer { /** * Constructs a panel for monitoring an automated ingest cluster. */ + @Messages({"AutoIngestDashboard.pendingTable.toolTipText=The Pending table displays the order upcoming Jobs will be processed with the top of the list first", + "AutoIngestDashboard.runningTable.toolTipText=The Running table displays the currently running Job and information about it", + "AutoIngestDashboard.completedTable.toolTipText=The Completed table shows all Jobs that have been processed already"}) + private AutoIngestDashboard() { this.statusByService = new ConcurrentHashMap<>(); @@ -108,6 +111,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); }); + pendingJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_pendingTable.toolTipText()); runningJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.RUNNING_JOB); runningJobsPanel.setSize(runningScrollPane.getSize()); runningScrollPane.add(runningJobsPanel); @@ -119,21 +123,23 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeJobButton.setEnabled(enabled); this.deprioritizeCaseButton.setEnabled(enabled); }); - finishedJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.COMPLETED_JOB); - finishedJobsPanel.setSize(completedScrollPane.getSize()); - completedScrollPane.add(finishedJobsPanel); - completedScrollPane.setViewportView(finishedJobsPanel); - finishedJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { + runningJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_runningTable.toolTipText()); + completedJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.COMPLETED_JOB); + completedJobsPanel.setSize(completedScrollPane.getSize()); + completedScrollPane.add(completedJobsPanel); + completedScrollPane.setViewportView(completedJobsPanel); + completedJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { boolean enabled = false; this.prioritizeJobButton.setEnabled(enabled); this.prioritizeCaseButton.setEnabled(enabled); this.deprioritizeJobButton.setEnabled(enabled); this.deprioritizeCaseButton.setEnabled(enabled); }); + completedJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_completedTable.toolTipText()); /* * Must set this flag, otherwise pop up menus don't close properly. */ - + UIManager.put("PopupMenu.consumeEventOnClose", false); } @@ -247,7 +253,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Override public void update(Observable observable, Object arg) { - EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); + EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); } /** @@ -259,9 +265,9 @@ final class AutoIngestDashboard extends JPanel implements Observer { private void refreshTables(JobsSnapshot jobsSnapshot) { pendingJobsPanel.refresh(jobsSnapshot); runningJobsPanel.refresh(jobsSnapshot); - finishedJobsPanel.refresh(jobsSnapshot); + completedJobsPanel.refresh(jobsSnapshot); } - + /** * Exception type thrown when there is an error completing an auto ingest * dashboard operation. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index ad8a92f97d..4ad3305045 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -119,24 +119,16 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa explorerManager.setRootContext(autoIngestNode); outline.setRowSelectionAllowed(true); if (selectedNodes.length > 0) { - setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())}); + try { + explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())}); + } catch (PropertyVetoException ignore) { + //Unable to select previously selected node + } + } } } - Node[] getSelectedNodes() { - return explorerManager.getSelectedNodes(); - } - - void setSelectedNodes(Node[] selectedRows) { - try { - explorerManager.setSelectedNodes(selectedRows); - } catch (PropertyVetoException ignore) { - System.out.println("Unable to set selected Rows: " + ignore.toString()); - //Unable to select previously selected node - } - } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always From 14d271bb28e3314eed4ceb7f9b5b6e4de896fc54 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 9 Apr 2018 17:04:51 -0400 Subject: [PATCH 16/64] 3610 add comments to clarifiy new methods and classes for outlineView aid2.0 --- .../autoingest/AutoIngestDashboard.java | 6 +- ...ngestNode.java => AutoIngestJobsNode.java} | 61 ++++++++++++++----- .../autoingest/AutoIngestJobsPanel.java | 50 ++++++++++----- 3 files changed, 86 insertions(+), 31 deletions(-) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/{AutoIngestNode.java => AutoIngestJobsNode.java} (78%) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 3d4a78f1ff..99e4deb600 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -90,7 +90,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { statusByService.put(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.MESSAGING.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); setServicesStatusMessage(); - pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.PENDING_JOB); + pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.PENDING_JOB); pendingJobsPanel.setSize(pendingScrollPane.getSize()); pendingScrollPane.add(pendingJobsPanel); pendingScrollPane.setViewportView(pendingJobsPanel); @@ -112,7 +112,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); }); pendingJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_pendingTable.toolTipText()); - runningJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.RUNNING_JOB); + runningJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.RUNNING_JOB); runningJobsPanel.setSize(runningScrollPane.getSize()); runningScrollPane.add(runningJobsPanel); runningScrollPane.setViewportView(runningJobsPanel); @@ -124,7 +124,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeCaseButton.setEnabled(enabled); }); runningJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_runningTable.toolTipText()); - completedJobsPanel = new AutoIngestJobsPanel(AutoIngestNode.AutoIngestJobType.COMPLETED_JOB); + completedJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.COMPLETED_JOB); completedJobsPanel.setSize(completedScrollPane.getSize()); completedScrollPane.add(completedJobsPanel); completedScrollPane.setViewportView(completedJobsPanel); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java similarity index 78% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index e6a4d19440..c71f0dcd55 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -33,7 +33,11 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnaps import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; -final class AutoIngestNode extends AbstractNode { +/** + * A node which represents all AutoIngestJobs of a given AutoIngestJobStatus. + * Each job with the specified status will have a child node representing it. + */ +final class AutoIngestJobsNode extends AbstractNode { @Messages({ "AutoIngestNode.caseName.text=Case Name", @@ -47,24 +51,37 @@ final class AutoIngestNode extends AbstractNode { "AutoIngestNode.status.text=Status" }) - AutoIngestNode(JobsSnapshot snapshot, AutoIngestJobType type) { - super(Children.create(new AutoIngestNodeChildren(snapshot, type), false)); + /** + * Construct a new AutoIngestJobsNode. + */ + AutoIngestJobsNode(JobsSnapshot snapshot, AutoIngestJobStatus status) { + super(Children.create(new AutoIngestNodeChildren(snapshot, status), false)); } + /** + * A ChildFactory for generating JobNodes. + */ static class AutoIngestNodeChildren extends ChildFactory { - private final AutoIngestJobType autoIngestJobType; + private final AutoIngestJobStatus autoIngestJobStatus; private final JobsSnapshot jobsSnapshot; - AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobType type) { + /** + * Create children nodes for the AutoIngestJobsNode which will each + * represent a single AutoIngestJob + * + * @param snapshot the snapshot which contains the AutoIngestJobs + * @param status the status of the jobs being displayed + */ + AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobStatus status) { jobsSnapshot = snapshot; - autoIngestJobType = type; + autoIngestJobStatus = status; } @Override protected boolean createKeys(List list) { List jobs; - switch (autoIngestJobType) { + switch (autoIngestJobStatus) { case PENDING_JOB: jobs = jobsSnapshot.getPendingJobs(); break; @@ -85,28 +102,40 @@ final class AutoIngestNode extends AbstractNode { @Override protected Node createNodeForKey(AutoIngestJob key) { - return new JobNode(key, autoIngestJobType); + return new JobNode(key, autoIngestJobStatus); } } /** - * A node which represents a single multi user case. + * A node which represents a single auto ingest job. */ static final class JobNode extends AbstractNode { private final AutoIngestJob autoIngestJob; - private final AutoIngestJobType jobType; + private final AutoIngestJobStatus jobStatus; - JobNode(AutoIngestJob job, AutoIngestJobType type) { + /** + * Construct a new JobNode to represent an AutoIngestJob and its status. + * + * @param job - the AutoIngestJob being represented by this node + * @param status - the current status of the AutoIngestJob being + * represented + */ + JobNode(AutoIngestJob job, AutoIngestJobStatus status) { super(Children.LEAF); - jobType = type; + jobStatus = status; autoIngestJob = job; super.setName(autoIngestJob.getManifest().getCaseName()); setName(autoIngestJob.getManifest().getCaseName()); setDisplayName(autoIngestJob.getManifest().getCaseName()); } + /** + * Get the AutoIngestJob which this node represents. + * + * @return autoIngestJob + */ AutoIngestJob getAutoIngestJob() { return autoIngestJob; } @@ -123,7 +152,7 @@ final class AutoIngestNode extends AbstractNode { autoIngestJob.getManifest().getCaseName())); ss.put(new NodeProperty<>(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); - switch (jobType) { + switch (jobStatus) { case PENDING_JOB: ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); @@ -153,7 +182,11 @@ final class AutoIngestNode extends AbstractNode { } } - enum AutoIngestJobType { + /** + * An enumeration used to indicate the current status of an auto ingest job + * node. + */ + enum AutoIngestJobStatus { PENDING_JOB, //NON-NLS RUNNING_JOB, //NON-NLS COMPLETED_JOB //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 4ad3305045..40c306ddd2 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -27,12 +27,11 @@ import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; import org.sleuthkit.autopsy.datamodel.EmptyNode; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.AutoIngestJobType; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNode.JobNode; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.AutoIngestJobStatus; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.JobNode; /** - * - * @author wschaefer + * A panel which displays an outline view with all jobs for a specified status. */ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerManager.Provider { @@ -40,22 +39,28 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; - private final AutoIngestJobType type; + private final AutoIngestJobStatus status; /** - * Creates new form PendingJobsPanel + * Creates a new AutoIngestJobsPanel of the specified jobStatus + * + * @param jobStatus the status of the jbos to be displayed on this panel */ - AutoIngestJobsPanel(AutoIngestJobType jobType) { + AutoIngestJobsPanel(AutoIngestJobStatus jobStatus) { initComponents(); - type = jobType; + status = jobStatus; outlineView = new org.openide.explorer.view.OutlineView(); outline = outlineView.getOutline(); customize(); } + /** + * Set up the AutoIngestJobsPanel's so that its outlineView is displaying + * the correct columns for the specified AutoIngestJobStatus + */ void customize() { - switch (type) { + switch (status) { case PENDING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), @@ -102,6 +107,12 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa outline.setPreferredScrollableViewportSize(new Dimension(400, 100)); } + /** + * Add a list selection listener to the selection model of the outline being + * used in this panel. + * + * @param listener the ListSelectionListener to add + */ void addListSelectionListener(ListSelectionListener listener) { outline.getSelectionModel().addListSelectionListener(listener); } @@ -111,20 +122,26 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa return explorerManager; } + /** + * Update the contents of this AutoIngestJobsPanel while retaining currently + * selected node. + * + * @param jobsSnapshot - the JobsSnapshot which will provide the new + * contents + */ void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { synchronized (this) { outline.setRowSelectionAllowed(false); Node[] selectedNodes = explorerManager.getSelectedNodes(); - AutoIngestNode autoIngestNode = new AutoIngestNode(jobsSnapshot, type); + AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(jobsSnapshot, status); explorerManager.setRootContext(autoIngestNode); outline.setRowSelectionAllowed(true); if (selectedNodes.length > 0) { try { - explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())}); - } catch (PropertyVetoException ignore) { + explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())}); + } catch (PropertyVetoException ignore) { //Unable to select previously selected node } - } } } @@ -141,8 +158,13 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa setLayout(new java.awt.BorderLayout()); }// //GEN-END:initComponents + /** + * Get the AutoIngestJob for the currently selected node of this panel. + * + * @return AutoIngestJob which is currently selected in this panel + */ AutoIngestJob getSelectedAutoIngestJob() { - Node[] selectedRows = getSelectedNodes(); + Node[] selectedRows = explorerManager.getSelectedNodes(); if (selectedRows.length == 1) { return ((JobNode) selectedRows[0]).getAutoIngestJob(); } From 30a364c4175156c0436173f1c58964f2f16f574e Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Tue, 10 Apr 2018 07:29:51 -0400 Subject: [PATCH 17/64] Minor cleanup from PR review --- .../autopsy/healthmonitor/ServicesHealthMonitor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java index c73fa55106..33855df091 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java @@ -310,13 +310,14 @@ public class ServicesHealthMonitor { timingMapCopy = new HashMap<>(timingInfoMap); timingInfoMap.clear(); } - logger.log(Level.INFO, "Writing health monitor metrics to database"); // Check if there's anything to report (right now we only have the timing map) if(timingMapCopy.keySet().isEmpty()) { return; } + logger.log(Level.INFO, "Writing health monitor metrics to database"); + // Write to the database CoordinationService.Lock lock = getSharedDbLock(); if(lock == null) { @@ -380,7 +381,6 @@ public class ServicesHealthMonitor { try (Connection connection = DriverManager.getConnection("jdbc:postgresql://" + db.getHost() + ":" + db.getPort() + "/postgres", db.getUserName(), db.getPassword()); //NON-NLS Statement statement = connection.createStatement();) { String createCommand = "SELECT 1 AS result FROM pg_database WHERE datname='" + DATABASE_NAME + "'"; - System.out.println(" query: " + createCommand); rs = statement.executeQuery(createCommand); if(rs.next()) { logger.log(Level.INFO, "Existing Services Health Monitor database found"); From 8de3dd76d37c3917c4b50adf642091bb1f89854d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 10 Apr 2018 16:26:15 -0400 Subject: [PATCH 18/64] Changed separator position to allow room for 'Translate Text'. --- Core/src/org/sleuthkit/autopsy/core/layer.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/layer.xml b/Core/src/org/sleuthkit/autopsy/core/layer.xml index 465529fa9f..79fa4d37ae 100644 --- a/Core/src/org/sleuthkit/autopsy/core/layer.xml +++ b/Core/src/org/sleuthkit/autopsy/core/layer.xml @@ -213,7 +213,7 @@ --> - + From 34ee030bd88a71ca80855253183efc38c33eb708 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 10 Apr 2018 17:09:11 -0400 Subject: [PATCH 19/64] 3610 add context menu options for priority changing to AID2.0 --- .../autoingest/AutoIngestDashboard.java | 132 ++++---------- .../AutoIngestDashboardTopComponent.java | 21 ++- .../autoingest/AutoIngestJobsNode.java | 47 ++++- .../autoingest/AutoIngestJobsPanel.java | 4 +- .../autoingest/PrioritizationAction.java | 162 ++++++++++++++++++ 5 files changed, 252 insertions(+), 114 deletions(-) create mode 100644 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 99e4deb600..ece26b0b71 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -37,8 +37,6 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; /** * A dashboard for monitoring an automated ingest cluster. @@ -90,7 +88,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { statusByService.put(ServicesMonitor.Service.REMOTE_KEYWORD_SEARCH.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); statusByService.put(ServicesMonitor.Service.MESSAGING.toString(), NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down")); setServicesStatusMessage(); - pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.PENDING_JOB); + pendingJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobStatus.PENDING_JOB); pendingJobsPanel.setSize(pendingScrollPane.getSize()); pendingScrollPane.add(pendingJobsPanel); pendingScrollPane.setViewportView(pendingJobsPanel); @@ -111,8 +109,8 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); }); - pendingJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_pendingTable.toolTipText()); - runningJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.RUNNING_JOB); + pendingJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_pendingTable_toolTipText()); + runningJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobStatus.RUNNING_JOB); runningJobsPanel.setSize(runningScrollPane.getSize()); runningScrollPane.add(runningJobsPanel); runningScrollPane.setViewportView(runningJobsPanel); @@ -123,8 +121,8 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeJobButton.setEnabled(enabled); this.deprioritizeCaseButton.setEnabled(enabled); }); - runningJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_runningTable.toolTipText()); - completedJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobType.COMPLETED_JOB); + runningJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_runningTable_toolTipText()); + completedJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobStatus.COMPLETED_JOB); completedJobsPanel.setSize(completedScrollPane.getSize()); completedScrollPane.add(completedJobsPanel); completedScrollPane.setViewportView(completedJobsPanel); @@ -135,7 +133,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { this.deprioritizeJobButton.setEnabled(enabled); this.deprioritizeCaseButton.setEnabled(enabled); }); - completedJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_completedTable.toolTipText()); + completedJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_completedTable_toolTipText()); /* * Must set this flag, otherwise pop up menus don't close properly. */ @@ -143,6 +141,14 @@ final class AutoIngestDashboard extends JPanel implements Observer { UIManager.put("PopupMenu.consumeEventOnClose", false); } + AutoIngestMonitor getMonitor() { + return autoIngestMonitor; + } + + AutoIngestJobsPanel getPendingJobsPanel() { + return pendingJobsPanel; + } + /** * Update status of the services on the dashboard */ @@ -253,7 +259,9 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Override public void update(Observable observable, Object arg) { - EventQueue.invokeLater(new RefreshComponentsTask((JobsSnapshot) arg)); + EventQueue.invokeLater(() -> { + refreshTables(); + }); } /** @@ -262,10 +270,10 @@ final class AutoIngestDashboard extends JPanel implements Observer { * * @param jobsSnapshot The jobs snapshot. */ - private void refreshTables(JobsSnapshot jobsSnapshot) { - pendingJobsPanel.refresh(jobsSnapshot); - runningJobsPanel.refresh(jobsSnapshot); - completedJobsPanel.refresh(jobsSnapshot); + private void refreshTables() { + pendingJobsPanel.refresh(autoIngestMonitor); + runningJobsPanel.refresh(autoIngestMonitor); + completedJobsPanel.refresh(autoIngestMonitor); } /** @@ -473,46 +481,13 @@ final class AutoIngestDashboard extends JPanel implements Observer { */ private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - JobsSnapshot jobsSnapshot = autoIngestMonitor.refreshJobsSnapshot(); - refreshTables(jobsSnapshot); + refreshTables(); setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_refreshButtonActionPerformed - @Messages({"AutoIngestDashboard.errorMessage.jobPrioritization=Failed to prioritize job \"%s\"."}) - private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed - AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); - if (job != null) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.prioritizeJob(job); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), job.getManifest().getFilePath()); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } - }//GEN-LAST:event_prioritizeJobButtonActionPerformed - @Messages({"AutoIngestDashboard.errorMessage.casePrioritization=Failed to prioritize case \"%s\"."}) private void prioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeCaseButtonActionPerformed - AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); - if (job != null) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = job.getManifest().getCaseName(); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.prioritizeCase(caseName); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), caseName); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } + new PrioritizationAction.PrioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_prioritizeCaseButtonActionPerformed private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed @@ -521,41 +496,19 @@ final class AutoIngestDashboard extends JPanel implements Observer { @Messages({"AutoIngestDashboard.errorMessage.jobDeprioritization=Failed to deprioritize job \"%s\"."}) private void deprioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeJobButtonActionPerformed - AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); - if (job != null) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.deprioritizeJob(job); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), job.getManifest().getFilePath()); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } + new PrioritizationAction.DeprioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_deprioritizeJobButtonActionPerformed @Messages({"AutoIngestDashboard.errorMessage.caseDeprioritization=Failed to deprioritize case \"%s\"."}) private void deprioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeCaseButtonActionPerformed - AutoIngestJob job = pendingJobsPanel.getSelectedAutoIngestJob(); - if (job != null) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - String caseName = job.getManifest().getCaseName(); - JobsSnapshot jobsSnapshot; - try { - jobsSnapshot = autoIngestMonitor.deprioritizeCase(caseName); - refreshTables(jobsSnapshot); - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), caseName); - LOGGER.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } - setCursor(Cursor.getDefaultCursor()); - } + new PrioritizationAction.DeprioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_deprioritizeCaseButtonActionPerformed + @Messages({"AutoIngestDashboard.errorMessage.jobPrioritization=Failed to prioritize job \"%s\"."}) + private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed + new PrioritizationAction.PrioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); + }//GEN-LAST:event_prioritizeJobButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; @@ -573,29 +526,4 @@ final class AutoIngestDashboard extends JPanel implements Observer { private javax.swing.JScrollPane runningScrollPane; private javax.swing.JTextField tbServicesStatusMessage; // End of variables declaration//GEN-END:variables - /** - * A task that refreshes the UI components on this panel to reflect a - * snapshot of the pending, running and completed auto ingest jobs lists of - * an auto ingest cluster. - */ - private class RefreshComponentsTask implements Runnable { - - private final JobsSnapshot jobsSnapshot; - - /** - * Constructs a task that refreshes the UI components on this panel to - * reflect a snapshot of the pending, running and completed auto ingest - * jobs lists of an auto ingest cluster. - * - * @param jobsSnapshot The jobs snapshot. - */ - RefreshComponentsTask(JobsSnapshot jobsSnapshot) { - this.jobsSnapshot = jobsSnapshot; - } - - @Override - public void run() { - refreshTables(jobsSnapshot); - } - } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java index 83bad29a99..54c7848b4f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Component; import java.util.List; import java.util.logging.Level; import java.util.stream.Collectors; @@ -74,7 +75,7 @@ public final class AutoIngestDashboardTopComponent extends TopComponent { AutoIngestDashboard dashboard = AutoIngestDashboard.createDashboard(); tc.add(dashboard); dashboard.setSize(dashboard.getPreferredSize()); - + tc.open(); } tc.toFront(); @@ -104,6 +105,24 @@ public final class AutoIngestDashboardTopComponent extends TopComponent { setName(Bundle.CTL_AutoIngestDashboardTopComponent()); } + AutoIngestMonitor getAutoIngestMonitor() { + for (Component comp : getComponents()) { + if (comp instanceof AutoIngestDashboard) { + return ((AutoIngestDashboard) comp).getMonitor(); + } + } + return null; + } + + AutoIngestJobsPanel getPendingJobsPanel() { + for (Component comp : getComponents()) { + if (comp instanceof AutoIngestDashboard) { + return ((AutoIngestDashboard) comp).getPendingJobsPanel(); + } + } + return null; + } + @Override public List availableModes(List modes) { /* diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index c71f0dcd55..cf6e4c7f29 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -18,6 +18,11 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.awt.Cursor; +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; import java.time.Instant; import java.util.ArrayList; import java.util.Date; @@ -28,8 +33,9 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.NodeProperty; -import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; @@ -54,8 +60,8 @@ final class AutoIngestJobsNode extends AbstractNode { /** * Construct a new AutoIngestJobsNode. */ - AutoIngestJobsNode(JobsSnapshot snapshot, AutoIngestJobStatus status) { - super(Children.create(new AutoIngestNodeChildren(snapshot, status), false)); + AutoIngestJobsNode(AutoIngestMonitor autoIngestMonitor, AutoIngestJobStatus status) { + super(Children.create(new AutoIngestNodeChildren(autoIngestMonitor, status), false)); } /** @@ -64,7 +70,7 @@ final class AutoIngestJobsNode extends AbstractNode { static class AutoIngestNodeChildren extends ChildFactory { private final AutoIngestJobStatus autoIngestJobStatus; - private final JobsSnapshot jobsSnapshot; + private final AutoIngestMonitor autoIngestMonitor; /** * Create children nodes for the AutoIngestJobsNode which will each @@ -73,8 +79,8 @@ final class AutoIngestJobsNode extends AbstractNode { * @param snapshot the snapshot which contains the AutoIngestJobs * @param status the status of the jobs being displayed */ - AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobStatus status) { - jobsSnapshot = snapshot; + AutoIngestNodeChildren(AutoIngestMonitor monitor, AutoIngestJobStatus status) { + autoIngestMonitor = monitor; autoIngestJobStatus = status; } @@ -83,13 +89,13 @@ final class AutoIngestJobsNode extends AbstractNode { List jobs; switch (autoIngestJobStatus) { case PENDING_JOB: - jobs = jobsSnapshot.getPendingJobs(); + jobs = autoIngestMonitor.refreshJobsSnapshot().getPendingJobs(); break; case RUNNING_JOB: - jobs = jobsSnapshot.getRunningJobs(); + jobs = autoIngestMonitor.refreshJobsSnapshot().getRunningJobs(); break; case COMPLETED_JOB: - jobs = jobsSnapshot.getCompletedJobs(); + jobs = autoIngestMonitor.refreshJobsSnapshot().getCompletedJobs(); break; default: jobs = new ArrayList<>(); @@ -180,6 +186,29 @@ final class AutoIngestJobsNode extends AbstractNode { } return s; } + + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + switch (jobStatus) { + case PENDING_JOB: + actions.add(new PrioritizationAction.PrioritizeJobAction(autoIngestJob)); + actions.add(new PrioritizationAction.PrioritizeCaseAction(autoIngestJob)); + PrioritizationAction.DeprioritizeJobAction deprioritizeJobAction = new PrioritizationAction.DeprioritizeJobAction(autoIngestJob); + deprioritizeJobAction.setEnabled(autoIngestJob.getPriority() > 0); + actions.add(deprioritizeJobAction); + PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(autoIngestJob); + deprioritizeCaseAction.setEnabled(autoIngestJob.getPriority() > 0); + actions.add(deprioritizeCaseAction); + break; + case RUNNING_JOB: + break; + case COMPLETED_JOB: + break; + default: + } + return actions.toArray(new Action[actions.size()]); + } } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 40c306ddd2..ecb829c288 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -129,11 +129,11 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa * @param jobsSnapshot - the JobsSnapshot which will provide the new * contents */ - void refresh(AutoIngestMonitor.JobsSnapshot jobsSnapshot) { + void refresh(AutoIngestMonitor autoIngestMonitor) { synchronized (this) { outline.setRowSelectionAllowed(false); Node[] selectedNodes = explorerManager.getSelectedNodes(); - AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(jobsSnapshot, status); + AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(autoIngestMonitor, status); explorerManager.setRootContext(autoIngestNode); outline.setRowSelectionAllowed(true); if (selectedNodes.length > 0) { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java new file mode 100644 index 0000000000..ce6e03071e --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -0,0 +1,162 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.experimental.autoingest; + +import java.awt.Cursor; +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; + +abstract class PrioritizationAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + private final AutoIngestJob job; + + PrioritizationAction(AutoIngestJob selectedJob, String title) { + super(title); + job = selectedJob; + } + + protected abstract void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException; + + protected abstract String getErrorMessage(); + + protected AutoIngestJob getJob() { + return job; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (job != null) { + final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(AutoIngestDashboardTopComponent.PREFERRED_ID); + if (tc != null) { + tc.getPendingJobsPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + EventQueue.invokeLater(() -> { + try { + AutoIngestMonitor monitor = tc.getAutoIngestMonitor(); + AutoIngestJobsPanel pendingPanel = tc.getPendingJobsPanel(); + if (monitor != null && pendingPanel != null) { + modifyPriority(monitor, pendingPanel); + } + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = getErrorMessage(); + // LOGGER.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } finally { + tc.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor()); + } + }); + } + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + + static final class PrioritizeJobAction extends PrioritizationAction { + + private static final long serialVersionUID = 1L; + + PrioritizeJobAction(AutoIngestJob selectedJob) { + super(selectedJob, "Prioritize Job"); + } + + @Override + protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + monitor.prioritizeJob(getJob()); + panel.refresh(monitor); + } + + @Override + protected String getErrorMessage() { + return String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), getJob().getManifest().getFilePath()); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } + + static final class DeprioritizeJobAction extends PrioritizationAction { + + private static final long serialVersionUID = 1L; + + DeprioritizeJobAction(AutoIngestJob selectedJob) { + super(selectedJob, "Deprioritize Job"); + } + + @Override + protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + monitor.deprioritizeJob(getJob()); + panel.refresh(monitor); + } + + @Override + protected String getErrorMessage() { + return String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), getJob().getManifest().getFilePath()); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } + + static final class PrioritizeCaseAction extends PrioritizationAction { + + private static final long serialVersionUID = 1L; + + PrioritizeCaseAction(AutoIngestJob selectedJob) { + super(selectedJob, "Prioritize Case"); + } + + @Override + protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + monitor.prioritizeCase(getJob().getManifest().getCaseName()); + panel.refresh(monitor); + } + + @Override + protected String getErrorMessage() { + return String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), getJob().getManifest().getCaseName()); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } + + static final class DeprioritizeCaseAction extends PrioritizationAction { + + private static final long serialVersionUID = 1L; + + DeprioritizeCaseAction(AutoIngestJob selectedJob) { + super(selectedJob, "Deprioritize Case"); + } + + @Override + protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + monitor.deprioritizeCase(getJob().getManifest().getCaseName()); + panel.refresh(monitor); + } + + @Override + protected String getErrorMessage() { + return String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), getJob().getManifest().getCaseName()); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } +} From a4d602933f30cb3e71f6d4bba8a38177758d4620 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 10 Apr 2018 17:37:09 -0400 Subject: [PATCH 20/64] 3610 change arguement back to being JobsSnapshot for refreshing --- .../autoingest/AutoIngestDashboard.java | 6 ++--- .../autoingest/AutoIngestJobsNode.java | 23 ++++++++----------- .../autoingest/AutoIngestJobsPanel.java | 5 ++-- .../autoingest/PrioritizationAction.java | 8 +++---- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index ece26b0b71..823f94c0a4 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -271,9 +271,9 @@ final class AutoIngestDashboard extends JPanel implements Observer { * @param jobsSnapshot The jobs snapshot. */ private void refreshTables() { - pendingJobsPanel.refresh(autoIngestMonitor); - runningJobsPanel.refresh(autoIngestMonitor); - completedJobsPanel.refresh(autoIngestMonitor); + pendingJobsPanel.refresh(autoIngestMonitor.getJobsSnapshot()); + runningJobsPanel.refresh(autoIngestMonitor.getJobsSnapshot()); + completedJobsPanel.refresh(autoIngestMonitor.getJobsSnapshot()); } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index cf6e4c7f29..ed99ac80fa 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -18,10 +18,6 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; -import java.awt.Cursor; -import java.awt.EventQueue; -import java.awt.event.ActionEvent; -import javax.swing.AbstractAction; import javax.swing.Action; import java.time.Instant; import java.util.ArrayList; @@ -33,9 +29,8 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; import org.sleuthkit.autopsy.guiutils.DurationCellRenderer; import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; @@ -60,8 +55,8 @@ final class AutoIngestJobsNode extends AbstractNode { /** * Construct a new AutoIngestJobsNode. */ - AutoIngestJobsNode(AutoIngestMonitor autoIngestMonitor, AutoIngestJobStatus status) { - super(Children.create(new AutoIngestNodeChildren(autoIngestMonitor, status), false)); + AutoIngestJobsNode(JobsSnapshot jobsSnapshot, AutoIngestJobStatus status) { + super(Children.create(new AutoIngestNodeChildren(jobsSnapshot, status), false)); } /** @@ -70,7 +65,7 @@ final class AutoIngestJobsNode extends AbstractNode { static class AutoIngestNodeChildren extends ChildFactory { private final AutoIngestJobStatus autoIngestJobStatus; - private final AutoIngestMonitor autoIngestMonitor; + private final JobsSnapshot jobsSnapshot; /** * Create children nodes for the AutoIngestJobsNode which will each @@ -79,8 +74,8 @@ final class AutoIngestJobsNode extends AbstractNode { * @param snapshot the snapshot which contains the AutoIngestJobs * @param status the status of the jobs being displayed */ - AutoIngestNodeChildren(AutoIngestMonitor monitor, AutoIngestJobStatus status) { - autoIngestMonitor = monitor; + AutoIngestNodeChildren(JobsSnapshot snapshot, AutoIngestJobStatus status) { + jobsSnapshot = snapshot; autoIngestJobStatus = status; } @@ -89,13 +84,13 @@ final class AutoIngestJobsNode extends AbstractNode { List jobs; switch (autoIngestJobStatus) { case PENDING_JOB: - jobs = autoIngestMonitor.refreshJobsSnapshot().getPendingJobs(); + jobs = jobsSnapshot.getPendingJobs(); break; case RUNNING_JOB: - jobs = autoIngestMonitor.refreshJobsSnapshot().getRunningJobs(); + jobs = jobsSnapshot.getRunningJobs(); break; case COMPLETED_JOB: - jobs = autoIngestMonitor.refreshJobsSnapshot().getCompletedJobs(); + jobs = jobsSnapshot.getCompletedJobs(); break; default: jobs = new ArrayList<>(); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index ecb829c288..5186d8797b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -29,6 +29,7 @@ import org.openide.nodes.Node; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.AutoIngestJobStatus; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.JobNode; +import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnapshot; /** * A panel which displays an outline view with all jobs for a specified status. @@ -129,11 +130,11 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa * @param jobsSnapshot - the JobsSnapshot which will provide the new * contents */ - void refresh(AutoIngestMonitor autoIngestMonitor) { + void refresh(JobsSnapshot jobsSnapshot) { synchronized (this) { outline.setRowSelectionAllowed(false); Node[] selectedNodes = explorerManager.getSelectedNodes(); - AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(autoIngestMonitor, status); + AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(jobsSnapshot, status); explorerManager.setRootContext(autoIngestNode); outline.setRowSelectionAllowed(true); if (selectedNodes.length > 0) { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java index ce6e03071e..bbf7bf4ffb 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -71,7 +71,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeJob(getJob()); - panel.refresh(monitor); + panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -96,7 +96,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeJob(getJob()); - panel.refresh(monitor); + panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -121,7 +121,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeCase(getJob().getManifest().getCaseName()); - panel.refresh(monitor); + panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -146,7 +146,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeCase(getJob().getManifest().getCaseName()); - panel.refresh(monitor); + panel.refresh(monitor.getJobsSnapshot()); } @Override From 3bdbdbae6a18fb5dab5f0366aa0c25e5a59feaf5 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 10 Apr 2018 17:52:32 -0400 Subject: [PATCH 21/64] 3610 add comments to PrioritizeAction and its subclasses --- .../autoingest/PrioritizationAction.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java index bbf7bf4ffb..7d9012dcf6 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -12,20 +12,52 @@ import javax.swing.AbstractAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +/** + * Abstract actions which are for the modification of AutoIngestJob or Case + * priority. + */ abstract class PrioritizationAction extends AbstractAction { private static final long serialVersionUID = 1L; private final AutoIngestJob job; + /** + * Construct a new Prioritization action for the selected job + * + * @param selectedJob The job which will be used to determine what has it's + * priority modified + * @param title - the string to represent the action in menus + */ PrioritizationAction(AutoIngestJob selectedJob, String title) { super(title); job = selectedJob; } + /** + * The implementation specific method which modifies job or case priority + * + * @param monitor - the AutoIngestMonitor which can be accessed to change + * the job or case priority + * @param panel - the AutoIngestJobsPanel which will need to be updated + * after the priority is modified + * + * @throws + * org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.AutoIngestMonitorException + */ protected abstract void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException; + /** + * Get the implementation specific error message for if modifyPriority fails + * + * @return the error message for the current implementation + */ protected abstract String getErrorMessage(); + /** + * Gets the job this action is constructed for + * + * @return job - the AutoIngestJob + */ protected AutoIngestJob getJob() { return job; } @@ -60,10 +92,18 @@ abstract class PrioritizationAction extends AbstractAction { return super.clone(); //To change body of generated methods, choose Tools | Templates. } + /** + * Action to prioritize the specified AutoIngestJob + */ static final class PrioritizeJobAction extends PrioritizationAction { private static final long serialVersionUID = 1L; + /** + * Construct a new PrioritizeJobAction + * + * @param selectedJob - the AutoIngestJob to be prioritized + */ PrioritizeJobAction(AutoIngestJob selectedJob) { super(selectedJob, "Prioritize Job"); } @@ -85,10 +125,18 @@ abstract class PrioritizationAction extends AbstractAction { } } + /** + * Action to deprioritize the specified AutoIngestJob + */ static final class DeprioritizeJobAction extends PrioritizationAction { private static final long serialVersionUID = 1L; + /** + * Construct a new DeprioritizeJobAction + * + * @param selectedJob - the AutoIngestJob to be deprioritized + */ DeprioritizeJobAction(AutoIngestJob selectedJob) { super(selectedJob, "Deprioritize Job"); } @@ -110,10 +158,20 @@ abstract class PrioritizationAction extends AbstractAction { } } + /** + * Action to prioritize all jobs for the case which the specified + * AutoIngestJob is a part of. + */ static final class PrioritizeCaseAction extends PrioritizationAction { private static final long serialVersionUID = 1L; + /** + * Construct a new PrioritizeCaseAction + * + * @param selectedJob - the AutoIngestJob which should have it's case + * prioritized + */ PrioritizeCaseAction(AutoIngestJob selectedJob) { super(selectedJob, "Prioritize Case"); } @@ -135,10 +193,20 @@ abstract class PrioritizationAction extends AbstractAction { } } + /** + * Action to deprioritize all jobs for the case which the specified + * AutoIngestJob is a part of. + */ static final class DeprioritizeCaseAction extends PrioritizationAction { private static final long serialVersionUID = 1L; + /** + * Construct a new DeprioritizeCaseAction + * + * @param selectedJob - the AutoIngestJob which should have it's case + * deprioritized + */ DeprioritizeCaseAction(AutoIngestJob selectedJob) { super(selectedJob, "Deprioritize Case"); } From 205f5b5bbe6dd47edecf2c4e00010e1ef86aeafb Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 10 Apr 2018 18:10:03 -0400 Subject: [PATCH 22/64] 3610 move bundle messages to where they are used --- .../autoingest/AutoIngestDashboard.java | 5 --- .../AutoIngestDashboardTopComponent.java | 14 ++++++ .../autoingest/PrioritizationAction.java | 44 ++++++++++++++----- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index 823f94c0a4..e5f150948d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -485,7 +485,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_refreshButtonActionPerformed - @Messages({"AutoIngestDashboard.errorMessage.casePrioritization=Failed to prioritize case \"%s\"."}) private void prioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeCaseButtonActionPerformed new PrioritizationAction.PrioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_prioritizeCaseButtonActionPerformed @@ -493,18 +492,14 @@ final class AutoIngestDashboard extends JPanel implements Observer { private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed new AutoIngestMetricsDialog(this.getTopLevelAncestor()); }//GEN-LAST:event_clusterMetricsButtonActionPerformed - - @Messages({"AutoIngestDashboard.errorMessage.jobDeprioritization=Failed to deprioritize job \"%s\"."}) private void deprioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeJobButtonActionPerformed new PrioritizationAction.DeprioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_deprioritizeJobButtonActionPerformed - @Messages({"AutoIngestDashboard.errorMessage.caseDeprioritization=Failed to deprioritize case \"%s\"."}) private void deprioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeCaseButtonActionPerformed new PrioritizationAction.DeprioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_deprioritizeCaseButtonActionPerformed - @Messages({"AutoIngestDashboard.errorMessage.jobPrioritization=Failed to prioritize job \"%s\"."}) private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed new PrioritizationAction.PrioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); }//GEN-LAST:event_prioritizeJobButtonActionPerformed diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java index 54c7848b4f..6b96c13609 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java @@ -105,6 +105,13 @@ public final class AutoIngestDashboardTopComponent extends TopComponent { setName(Bundle.CTL_AutoIngestDashboardTopComponent()); } + /** + * Get the AutoIngestMonitor from the current AutoIngestDashboard if there + * is one. + * + * @return the current AutoIngestMonitor or null if there is no + * AutoIngestDashboard + */ AutoIngestMonitor getAutoIngestMonitor() { for (Component comp : getComponents()) { if (comp instanceof AutoIngestDashboard) { @@ -114,6 +121,13 @@ public final class AutoIngestDashboardTopComponent extends TopComponent { return null; } + /** + * Get the pending jobs panel from the current AutoIngestDashboard if there + * is one. + * + * @return the AutoIngestJobsPanel which contains the pending AutoIngestJobs + * or null if there is no AutoIngestDashboard + */ AutoIngestJobsPanel getPendingJobsPanel() { for (Component comp : getComponents()) { if (comp instanceof AutoIngestDashboard) { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java index 7d9012dcf6..ba461077a6 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.experimental.autoingest; @@ -9,6 +22,7 @@ import java.awt.Cursor; import java.awt.EventQueue; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; +import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; @@ -95,6 +109,8 @@ abstract class PrioritizationAction extends AbstractAction { /** * Action to prioritize the specified AutoIngestJob */ + @Messages({"PrioritizationAction.prioritizeJobAction.title=Prioritize Job", + "PrioritizationAction.prioritizeJobAction.error=Failed to prioritize job \"%s\"."}) static final class PrioritizeJobAction extends PrioritizationAction { private static final long serialVersionUID = 1L; @@ -105,7 +121,7 @@ abstract class PrioritizationAction extends AbstractAction { * @param selectedJob - the AutoIngestJob to be prioritized */ PrioritizeJobAction(AutoIngestJob selectedJob) { - super(selectedJob, "Prioritize Job"); + super(selectedJob, Bundle.PrioritizationAction_prioritizeJobAction_title()); } @Override @@ -116,7 +132,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected String getErrorMessage() { - return String.format(Bundle.AutoIngestDashboard_errorMessage_jobPrioritization(), getJob().getManifest().getFilePath()); + return String.format(Bundle.PrioritizationAction_prioritizeJobAction_error(), getJob().getManifest().getFilePath()); } @Override @@ -128,6 +144,8 @@ abstract class PrioritizationAction extends AbstractAction { /** * Action to deprioritize the specified AutoIngestJob */ + @Messages({"PrioritizationAction.deprioritizeJobAction.title=Deprioritize Job", + "PrioritizationAction.deprioritizeJobAction.error=Failed to deprioritize job \"%s\"."}) static final class DeprioritizeJobAction extends PrioritizationAction { private static final long serialVersionUID = 1L; @@ -138,7 +156,7 @@ abstract class PrioritizationAction extends AbstractAction { * @param selectedJob - the AutoIngestJob to be deprioritized */ DeprioritizeJobAction(AutoIngestJob selectedJob) { - super(selectedJob, "Deprioritize Job"); + super(selectedJob, Bundle.PrioritizationAction_deprioritizeJobAction_title()); } @Override @@ -149,7 +167,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected String getErrorMessage() { - return String.format(Bundle.AutoIngestDashboard_errorMessage_jobDeprioritization(), getJob().getManifest().getFilePath()); + return String.format(Bundle.PrioritizationAction_deprioritizeJobAction_error(), getJob().getManifest().getFilePath()); } @Override @@ -162,6 +180,8 @@ abstract class PrioritizationAction extends AbstractAction { * Action to prioritize all jobs for the case which the specified * AutoIngestJob is a part of. */ + @Messages({"PrioritizationAction.prioritizeCaseAction.title=Prioritize Case", + "PrioritizationAction.prioritizeCaseAction.error==Failed to prioritize case \"%s\"."}) static final class PrioritizeCaseAction extends PrioritizationAction { private static final long serialVersionUID = 1L; @@ -173,7 +193,7 @@ abstract class PrioritizationAction extends AbstractAction { * prioritized */ PrioritizeCaseAction(AutoIngestJob selectedJob) { - super(selectedJob, "Prioritize Case"); + super(selectedJob, Bundle.PrioritizationAction_prioritizeCaseAction_title()); } @Override @@ -184,7 +204,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected String getErrorMessage() { - return String.format(Bundle.AutoIngestDashboard_errorMessage_casePrioritization(), getJob().getManifest().getCaseName()); + return String.format(Bundle.PrioritizationAction_prioritizeCaseAction_error(), getJob().getManifest().getCaseName()); } @Override @@ -197,6 +217,8 @@ abstract class PrioritizationAction extends AbstractAction { * Action to deprioritize all jobs for the case which the specified * AutoIngestJob is a part of. */ + @Messages({"PrioritizationAction.deprioritizeCaseAction.title=Deprioritize Case", + "PrioritizationAction.deprioritizeCaseAction.error=Failed to deprioritize case \"%s\"."}) static final class DeprioritizeCaseAction extends PrioritizationAction { private static final long serialVersionUID = 1L; @@ -208,7 +230,7 @@ abstract class PrioritizationAction extends AbstractAction { * deprioritized */ DeprioritizeCaseAction(AutoIngestJob selectedJob) { - super(selectedJob, "Deprioritize Case"); + super(selectedJob, Bundle.PrioritizationAction_deprioritizeCaseAction_title()); } @Override @@ -219,7 +241,7 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected String getErrorMessage() { - return String.format(Bundle.AutoIngestDashboard_errorMessage_caseDeprioritization(), getJob().getManifest().getCaseName()); + return String.format(Bundle.PrioritizationAction_deprioritizeCaseAction_error(), getJob().getManifest().getCaseName()); } @Override From 85dff9aee439cd427099f10bbb0b6f66eea86100 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 10 Apr 2018 18:21:50 -0400 Subject: [PATCH 23/64] 3610 add logger usage to new PrioritizationAction class --- .../experimental/autoingest/PrioritizationAction.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java index ba461077a6..14e2fed384 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -21,9 +21,11 @@ package org.sleuthkit.autopsy.experimental.autoingest; import java.awt.Cursor; import java.awt.EventQueue; import java.awt.event.ActionEvent; +import java.util.logging.Level; import javax.swing.AbstractAction; import org.openide.util.NbBundle.Messages; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** @@ -33,6 +35,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; abstract class PrioritizationAction extends AbstractAction { private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(PrioritizationAction.class.getName()); private final AutoIngestJob job; /** @@ -88,10 +91,11 @@ abstract class PrioritizationAction extends AbstractAction { AutoIngestJobsPanel pendingPanel = tc.getPendingJobsPanel(); if (monitor != null && pendingPanel != null) { modifyPriority(monitor, pendingPanel); + pendingPanel.refresh(monitor.getJobsSnapshot()); } } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { String errorMessage = getErrorMessage(); - // LOGGER.log(Level.SEVERE, errorMessage, ex); + logger.log(Level.SEVERE, errorMessage, ex); MessageNotifyUtil.Message.error(errorMessage); } finally { tc.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor()); @@ -127,7 +131,6 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeJob(getJob()); - panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -162,7 +165,6 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeJob(getJob()); - panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -199,7 +201,6 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeCase(getJob().getManifest().getCaseName()); - panel.refresh(monitor.getJobsSnapshot()); } @Override @@ -236,7 +237,6 @@ abstract class PrioritizationAction extends AbstractAction { @Override protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeCase(getJob().getManifest().getCaseName()); - panel.refresh(monitor.getJobsSnapshot()); } @Override From 2ba0df6f8c136845641cff43eeb64e72b83dafa5 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 11 Apr 2018 14:34:50 -0400 Subject: [PATCH 24/64] Code cleanup and renaming to address PR review comments. --- ...itor.java => EnterpriseHealthMonitor.java} | 114 ++++++++++-------- .../HealthMonitorCaseEventListener.java | 53 -------- .../autopsy/healthmonitor/Installer.java | 5 +- .../autopsy/keywordsearch/Ingester.java | 6 +- .../autopsy/keywordsearch/Server.java | 6 +- 5 files changed, 73 insertions(+), 111 deletions(-) rename Core/src/org/sleuthkit/autopsy/healthmonitor/{ServicesHealthMonitor.java => EnterpriseHealthMonitor.java} (89%) delete mode 100644 Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/EnterpriseHealthMonitor.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java rename to Core/src/org/sleuthkit/autopsy/healthmonitor/EnterpriseHealthMonitor.java index 33855df091..35bc6b6bfa 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/ServicesHealthMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/EnterpriseHealthMonitor.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.healthmonitor; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -27,16 +29,21 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.Map; import java.util.HashMap; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import org.apache.commons.dbcp2.BasicDataSource; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferencesException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.datamodel.CaseDbConnectionInfo; import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; @@ -47,18 +54,21 @@ import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; * Modules will call getTimingMetric() before the code to be timed to get a TimingMetric object * Modules will call submitTimingMetric() with the obtained TimingMetric object to log it */ -public class ServicesHealthMonitor { +public final class EnterpriseHealthMonitor implements PropertyChangeListener { - private final static Logger logger = Logger.getLogger(ServicesHealthMonitor.class.getName()); - private final static String DATABASE_NAME = "ServicesHealthMonitor"; - private final static String MODULE_NAME = "ServicesHealthMonitor"; + private final static Logger logger = Logger.getLogger(EnterpriseHealthMonitor.class.getName()); + private final static String DATABASE_NAME = "EnterpriseHealthMonitor"; + private final static String MODULE_NAME = "EnterpriseHealthMonitor"; private final static String IS_ENABLED_KEY = "is_enabled"; private final static long DATABASE_WRITE_INTERVAL = 60; // Minutes public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 0); private static final AtomicBoolean isEnabled = new AtomicBoolean(false); - private static ServicesHealthMonitor instance; + private static EnterpriseHealthMonitor instance; + + private final ExecutorService healthMonitorExecutor; + private static final String HEALTH_MONITOR_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d"; private ScheduledThreadPoolExecutor healthMonitorOutputTimer; private final Map timingInfoMap; @@ -66,19 +76,22 @@ public class ServicesHealthMonitor { private BasicDataSource connectionPool = null; private String hostName; - private ServicesHealthMonitor() throws HealthMonitorException { + private EnterpriseHealthMonitor() throws HealthMonitorException { // Create the map to collect timing metrics. The map will exist regardless // of whether the monitor is enabled. timingInfoMap = new HashMap<>(); + // Set up the executor to handle case events + healthMonitorExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(HEALTH_MONITOR_EVENT_THREAD_NAME).build()); + // Get the host name try { hostName = java.net.InetAddress.getLocalHost().getHostName(); } catch (java.net.UnknownHostException ex) { - // Continue on but log a warning - logger.log(Level.WARNING, "Unable to look up host name"); - hostName = "unknown"; + // Continue on, but log the error and generate a UUID to use for this session + hostName = UUID.randomUUID().toString(); + logger.log(Level.SEVERE, "Unable to look up host name - falling back to UUID " + hostName, ex); } // Read from module settings to determine if the module is enabled @@ -100,13 +113,14 @@ public class ServicesHealthMonitor { } /** - * Get the instance of the ServicesHealthMonitor + * Get the instance of the EnterpriseHealthMonitor * @return the instance * @throws HealthMonitorException */ - synchronized static ServicesHealthMonitor getInstance() throws HealthMonitorException { + synchronized static EnterpriseHealthMonitor getInstance() throws HealthMonitorException { if (instance == null) { - instance = new ServicesHealthMonitor(); + instance = new EnterpriseHealthMonitor(); + Case.addPropertyChangeListener(instance); } return instance; } @@ -122,15 +136,15 @@ public class ServicesHealthMonitor { logger.log(Level.INFO, "Activating Servies Health Monitor"); if (!UserPreferences.getIsMultiUserModeEnabled()) { - throw new HealthMonitorException("Multi user mode is not enabled - can not activate services health monitor"); - } - // Set up database (if needed) - CoordinationService.Lock lock = getExclusiveDbLock(); - if(lock == null) { - throw new HealthMonitorException("Error getting database lock"); + throw new HealthMonitorException("Multi user mode is not enabled - can not activate health monitor"); } - try { + // Set up database (if needed) + try (CoordinationService.Lock lock = getExclusiveDbLock()) { + if(lock == null) { + throw new HealthMonitorException("Error getting database lock"); + } + // Check if the database exists if (! databaseExists()) { @@ -142,12 +156,8 @@ public class ServicesHealthMonitor { initializeDatabaseSchema(); } - } finally { - try { - lock.release(); - } catch (CoordinationService.CoordinationServiceException ex) { - throw new HealthMonitorException("Error releasing database lock", ex); - } + } catch (CoordinationService.CoordinationServiceException ex) { + throw new HealthMonitorException("Error releasing database lock", ex); } // Clear out any old data @@ -182,10 +192,9 @@ public class ServicesHealthMonitor { * Start the ScheduledThreadPoolExecutor that will handle the database writes. */ private synchronized void startTimer() { - if(healthMonitorOutputTimer != null) { - // Make sure the previous executor (if it exists) has been stopped - healthMonitorOutputTimer.shutdown(); - } + // Make sure the previous executor (if it exists) has been stopped + stopTimer(); + healthMonitorOutputTimer = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("health_monitor_timer").build()); healthMonitorOutputTimer.scheduleWithFixedDelay(new DatabaseWriteTask(), DATABASE_WRITE_INTERVAL, DATABASE_WRITE_INTERVAL, TimeUnit.MINUTES); } @@ -195,7 +204,7 @@ public class ServicesHealthMonitor { */ private synchronized void stopTimer() { if(healthMonitorOutputTimer != null) { - healthMonitorOutputTimer.shutdown(); + ThreadUtils.shutDownTaskExecutor(healthMonitorOutputTimer); } } @@ -203,7 +212,7 @@ public class ServicesHealthMonitor { * Called from the installer to set up the Health Monitor instance at startup. * @throws HealthMonitorException */ - static synchronized void startUp() throws HealthMonitorException { + static synchronized void startUpIfEnabled() throws HealthMonitorException { getInstance(); } @@ -235,7 +244,7 @@ public class ServicesHealthMonitor { * Get a metric that will measure the time to execute a section of code. * Call this before the section of code to be timed and then * submit it afterward using submitTimingMetric(). - * This method is safe to call regardless of whether the Services Health + * This method is safe to call regardless of whether the Enterprise Health * Monitor is enabled. * @param name A short but descriptive name describing the code being timed. * This name will appear in the UI. @@ -251,7 +260,7 @@ public class ServicesHealthMonitor { /** * Submit the metric that was previously obtained through getTimingMetric(). * Call this immediately after the section of code being timed. - * This method is safe to call regardless of whether the Services Health + * This method is safe to call regardless of whether the Enterprise Health * Monitor is enabled. * @param metric The TimingMetric object obtained from getTimingMetric() */ @@ -318,13 +327,12 @@ public class ServicesHealthMonitor { logger.log(Level.INFO, "Writing health monitor metrics to database"); - // Write to the database - CoordinationService.Lock lock = getSharedDbLock(); - if(lock == null) { - throw new HealthMonitorException("Error getting database lock"); - } - - try { + // Write to the database + try (CoordinationService.Lock lock = getSharedDbLock()) { + if(lock == null) { + throw new HealthMonitorException("Error getting database lock"); + } + Connection conn = connect(); if(conn == null) { throw new HealthMonitorException("Error getting database connection"); @@ -357,12 +365,8 @@ public class ServicesHealthMonitor { logger.log(Level.SEVERE, "Error closing Connection.", ex); } } - } finally { - try { - lock.release(); - } catch (CoordinationService.CoordinationServiceException ex) { - throw new HealthMonitorException("Error releasing database lock", ex); - } + } catch (CoordinationService.CoordinationServiceException ex) { + throw new HealthMonitorException("Error releasing database lock", ex); } } @@ -383,7 +387,7 @@ public class ServicesHealthMonitor { String createCommand = "SELECT 1 AS result FROM pg_database WHERE datname='" + DATABASE_NAME + "'"; rs = statement.executeQuery(createCommand); if(rs.next()) { - logger.log(Level.INFO, "Existing Services Health Monitor database found"); + logger.log(Level.INFO, "Existing Enterprise Health Monitor database found"); return true; } } finally { @@ -648,6 +652,20 @@ public class ServicesHealthMonitor { } } + @Override + public void propertyChange(PropertyChangeEvent evt) { + + switch (Case.Events.valueOf(evt.getPropertyName())) { + + case CURRENT_CASE: + if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof Case)) { + // When a case is closed, write the current metrics to the database + healthMonitorExecutor.submit(new EnterpriseHealthMonitor.DatabaseWriteTask()); + } + break; + } + } + /** * Get an exclusive lock for the health monitor database. * Acquire this before creating, initializing, or updating the database schema. @@ -663,7 +681,7 @@ public class ServicesHealthMonitor { } throw new HealthMonitorException("Error acquiring database lock"); } catch (InterruptedException | CoordinationService.CoordinationServiceException ex){ - throw new HealthMonitorException("Error acquiring database lock"); + throw new HealthMonitorException("Error acquiring database lock", ex); } } diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java deleted file mode 100644 index f6c5583692..0000000000 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/HealthMonitorCaseEventListener.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2018 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.healthmonitor; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import org.sleuthkit.autopsy.casemodule.Case; - -/** - * Listener for case events - */ -final class HealthMonitorCaseEventListener implements PropertyChangeListener { - - private final ExecutorService healthMonitorExecutor; - private static final String HEALTH_MONITOR_EVENT_THREAD_NAME = "Health-Monitor-Event-Listener-%d"; - - HealthMonitorCaseEventListener() { - healthMonitorExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(HEALTH_MONITOR_EVENT_THREAD_NAME).build()); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - - switch (Case.Events.valueOf(evt.getPropertyName())) { - - case CURRENT_CASE: - if ((null == evt.getNewValue()) && (evt.getOldValue() instanceof Case)) { - // When a case is closed, write the current metrics to the database - healthMonitorExecutor.submit(new ServicesHealthMonitor.DatabaseWriteTask()); - } - break; - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java index 5d294aca31..61ea5a5244 100644 --- a/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/healthmonitor/Installer.java @@ -26,7 +26,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; public class Installer extends ModuleInstall { private static final Logger logger = Logger.getLogger(Installer.class.getName()); - private final HealthMonitorCaseEventListener pcl = new HealthMonitorCaseEventListener(); private static final long serialVersionUID = 1L; private static Installer instance; @@ -45,10 +44,8 @@ public class Installer extends ModuleInstall { @Override public void restored() { - Case.addPropertyChangeListener(pcl); - try { - ServicesHealthMonitor.startUp(); + EnterpriseHealthMonitor.startUpIfEnabled(); } catch (HealthMonitorException ex) { logger.log(Level.SEVERE, "Error starting health services monitor", ex); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index f956513eca..b9c4541c7b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -27,7 +27,7 @@ import org.apache.solr.common.SolrInputDocument; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; -import org.sleuthkit.autopsy.healthmonitor.ServicesHealthMonitor; +import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor; import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.keywordsearch.Chunker.Chunk; @@ -237,9 +237,9 @@ class Ingester { try { //TODO: consider timeout thread, or vary socket timeout based on size of indexed content - TimingMetric metric = ServicesHealthMonitor.getTimingMetric("Solr: Index chunk"); + TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk"); solrServer.addDocument(updateDoc); - ServicesHealthMonitor.submitTimingMetric(metric); + EnterpriseHealthMonitor.submitTimingMetric(metric); uncommitedIngests = true; } catch (KeywordSearchModuleException | NoOpenCoreException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 5748524ada..eea4d2914e 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -70,7 +70,7 @@ import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.healthmonitor.ServicesHealthMonitor; +import org.sleuthkit.autopsy.healthmonitor.EnterpriseHealthMonitor; import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchServiceException; import org.sleuthkit.datamodel.Content; @@ -775,9 +775,9 @@ public class Server { IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory()); currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS } - TimingMetric metric = ServicesHealthMonitor.getTimingMetric("Solr: Connectivity check"); + TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check"); connectToSolrServer(currentSolrServer); - ServicesHealthMonitor.submitTimingMetric(metric); + EnterpriseHealthMonitor.submitTimingMetric(metric); } catch (SolrServerException | IOException ex) { throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex); From eb898c5fcecba7323ec0805a86d302642a3b8f29 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Apr 2018 15:48:29 -0400 Subject: [PATCH 25/64] 3610 Priority column now displays yes or no for prioritized --- .../AutoIngestDashboardTopComponent.form | 2 +- .../AutoIngestDashboardTopComponent.java | 26 ++--------- .../autoingest/AutoIngestJobsNode.java | 44 ++++++++++--------- .../autoingest/AutoIngestJobsPanel.java | 26 +++++------ .../autoingest/PrioritizationAction.java | 43 +++++++++--------- 5 files changed, 61 insertions(+), 80 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form index 63887aceb0..5f3eab1a5f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.form @@ -25,4 +25,4 @@
- \ No newline at end of file + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java index 6b96c13609..9a5553519c 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboardTopComponent.java @@ -106,32 +106,14 @@ public final class AutoIngestDashboardTopComponent extends TopComponent { } /** - * Get the AutoIngestMonitor from the current AutoIngestDashboard if there - * is one. + * Get the current AutoIngestDashboard if there is one. * - * @return the current AutoIngestMonitor or null if there is no - * AutoIngestDashboard + * @return the current AutoIngestDashboard or null if there is not one */ - AutoIngestMonitor getAutoIngestMonitor() { + AutoIngestDashboard getAutoIngestDashboard() { for (Component comp : getComponents()) { if (comp instanceof AutoIngestDashboard) { - return ((AutoIngestDashboard) comp).getMonitor(); - } - } - return null; - } - - /** - * Get the pending jobs panel from the current AutoIngestDashboard if there - * is one. - * - * @return the AutoIngestJobsPanel which contains the pending AutoIngestJobs - * or null if there is no AutoIngestDashboard - */ - AutoIngestJobsPanel getPendingJobsPanel() { - for (Component comp : getComponents()) { - if (comp instanceof AutoIngestDashboard) { - return ((AutoIngestDashboard) comp).getPendingJobsPanel(); + return (AutoIngestDashboard) comp; } } return null; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index ed99ac80fa..0e5e94159c 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -41,15 +41,15 @@ import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; final class AutoIngestJobsNode extends AbstractNode { @Messages({ - "AutoIngestNode.caseName.text=Case Name", - "AutoIngestNode.dataSource.text=Data Source", - "AutoIngestNode.hostName.text=Host Name", - "AutoIngestNode.stage.text=Stage", - "AutoIngestNode.stageTime.text=Time in Stage", - "AutoIngestNode.jobCreated.text=Job Created", - "AutoIngestNode.jobCompleted.text=Job Completed", - "AutoIngestNode.priority.text=Priority", - "AutoIngestNode.status.text=Status" + "AutoIngestJobsNode.caseName.text=Case Name", + "AutoIngestJobsNode.dataSource.text=Data Source", + "AutoIngestJobsNode.hostName.text=Host Name", + "AutoIngestJobsNode.stage.text=Stage", + "AutoIngestJobsNode.stageTime.text=Time in Stage", + "AutoIngestJobsNode.jobCreated.text=Job Created", + "AutoIngestJobsNode.jobCompleted.text=Job Completed", + "AutoIngestJobsNode.priority.text=Prioritized", + "AutoIngestJobsNode.status.text=Status" }) /** @@ -85,6 +85,7 @@ final class AutoIngestJobsNode extends AbstractNode { switch (autoIngestJobStatus) { case PENDING_JOB: jobs = jobsSnapshot.getPendingJobs(); + jobs.sort(new AutoIngestJob.PriorityComparator()); break; case RUNNING_JOB: jobs = jobsSnapshot.getRunningJobs(); @@ -142,6 +143,9 @@ final class AutoIngestJobsNode extends AbstractNode { } @Override + @Messages({"AutoIngestJobsNode.prioritized.true=Yes", + "AutoIngestJobsNode.prioritized.false=No" + }) protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); @@ -149,32 +153,32 @@ final class AutoIngestJobsNode extends AbstractNode { ss = Sheet.createPropertiesSet(); s.put(ss); } - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), Bundle.AutoIngestNode_caseName_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_caseName_text(), Bundle.AutoIngestJobsNode_caseName_text(), Bundle.AutoIngestJobsNode_caseName_text(), autoIngestJob.getManifest().getCaseName())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), autoIngestJob.getManifest().getDataSourcePath().getFileName().toString())); switch (jobStatus) { case PENDING_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text(), - autoIngestJob.getPriority())); + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), + autoIngestJob.getPriority() > 0 ? Bundle.AutoIngestJobsNode_prioritized_true() : Bundle.AutoIngestJobsNode_prioritized_false())); break; case RUNNING_JOB: AutoIngestJob.StageDetails status = autoIngestJob.getProcessingStageDetails(); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), autoIngestJob.getProcessingHostName())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), status.getDescription())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text(), DurationCellRenderer.longToDurationString((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())))); break; case COMPLETED_JOB: - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), autoIngestJob.getManifest().getDateFileCreated())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), autoIngestJob.getCompletedDate())); - ss.put(new NodeProperty<>(Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text(), + ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(), autoIngestJob.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK)); break; default: diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 5186d8797b..e21d8f569c 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -63,29 +63,27 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa switch (status) { case PENDING_JOB: - outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), - Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), - Bundle.AutoIngestNode_priority_text(), Bundle.AutoIngestNode_priority_text()); - outline.setColumnSorted(3, false, 1); - outline.setColumnSorted(0, true, 2); + outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), + Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), + Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text()); break; case RUNNING_JOB: - outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), - Bundle.AutoIngestNode_hostName_text(), Bundle.AutoIngestNode_hostName_text(), - Bundle.AutoIngestNode_stage_text(), Bundle.AutoIngestNode_stage_text(), - Bundle.AutoIngestNode_stageTime_text(), Bundle.AutoIngestNode_stageTime_text()); + outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), + Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), + Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), + Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text()); outline.setColumnSorted(0, true, 1); break; case COMPLETED_JOB: - outlineView.setPropertyColumns(Bundle.AutoIngestNode_dataSource_text(), Bundle.AutoIngestNode_dataSource_text(), - Bundle.AutoIngestNode_jobCreated_text(), Bundle.AutoIngestNode_jobCreated_text(), - Bundle.AutoIngestNode_jobCompleted_text(), Bundle.AutoIngestNode_jobCompleted_text(), - Bundle.AutoIngestNode_status_text(), Bundle.AutoIngestNode_status_text()); + outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), + Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), + Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), + Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text()); outline.setColumnSorted(3, false, 1); break; default: } - ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestNode_caseName_text()); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestJobsNode_caseName_text()); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); outline.setRootVisible(false); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java index 14e2fed384..d50a85f906 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PrioritizationAction.java @@ -55,13 +55,11 @@ abstract class PrioritizationAction extends AbstractAction { * * @param monitor - the AutoIngestMonitor which can be accessed to change * the job or case priority - * @param panel - the AutoIngestJobsPanel which will need to be updated - * after the priority is modified * * @throws * org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.AutoIngestMonitorException */ - protected abstract void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException; + protected abstract void modifyPriority(AutoIngestMonitor monitor) throws AutoIngestMonitor.AutoIngestMonitorException; /** * Get the implementation specific error message for if modifyPriority fails @@ -84,23 +82,22 @@ abstract class PrioritizationAction extends AbstractAction { if (job != null) { final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(AutoIngestDashboardTopComponent.PREFERRED_ID); if (tc != null) { - tc.getPendingJobsPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - EventQueue.invokeLater(() -> { - try { - AutoIngestMonitor monitor = tc.getAutoIngestMonitor(); - AutoIngestJobsPanel pendingPanel = tc.getPendingJobsPanel(); - if (monitor != null && pendingPanel != null) { - modifyPriority(monitor, pendingPanel); - pendingPanel.refresh(monitor.getJobsSnapshot()); + AutoIngestDashboard dashboard = tc.getAutoIngestDashboard(); + if (dashboard != null) { + dashboard.getPendingJobsPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + EventQueue.invokeLater(() -> { + try { + modifyPriority(dashboard.getMonitor()); + dashboard.getPendingJobsPanel().refresh(dashboard.getMonitor().getJobsSnapshot()); + } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { + String errorMessage = getErrorMessage(); + logger.log(Level.SEVERE, errorMessage, ex); + MessageNotifyUtil.Message.error(errorMessage); + } finally { + dashboard.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor()); } - } catch (AutoIngestMonitor.AutoIngestMonitorException ex) { - String errorMessage = getErrorMessage(); - logger.log(Level.SEVERE, errorMessage, ex); - MessageNotifyUtil.Message.error(errorMessage); - } finally { - tc.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor()); - } - }); + }); + } } } } @@ -129,7 +126,7 @@ abstract class PrioritizationAction extends AbstractAction { } @Override - protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + protected void modifyPriority(AutoIngestMonitor monitor) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeJob(getJob()); } @@ -163,7 +160,7 @@ abstract class PrioritizationAction extends AbstractAction { } @Override - protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + protected void modifyPriority(AutoIngestMonitor monitor) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeJob(getJob()); } @@ -199,7 +196,7 @@ abstract class PrioritizationAction extends AbstractAction { } @Override - protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + protected void modifyPriority(AutoIngestMonitor monitor) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.prioritizeCase(getJob().getManifest().getCaseName()); } @@ -235,7 +232,7 @@ abstract class PrioritizationAction extends AbstractAction { } @Override - protected void modifyPriority(AutoIngestMonitor monitor, AutoIngestJobsPanel panel) throws AutoIngestMonitor.AutoIngestMonitorException { + protected void modifyPriority(AutoIngestMonitor monitor) throws AutoIngestMonitor.AutoIngestMonitorException { monitor.deprioritizeCase(getJob().getManifest().getCaseName()); } From 472a0d1104446c4d8d7f47dcf9a7c0a77b42b153 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 11 Apr 2018 16:44:01 -0400 Subject: [PATCH 26/64] 3610 clean up of resizing and sorting columns in outline view AID2.0 --- .../autoingest/AutoIngestJobsPanel.java | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index e21d8f569c..4cb237f1a8 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -26,6 +26,7 @@ import org.netbeans.swing.outline.DefaultOutlineModel; import org.netbeans.swing.outline.Outline; import org.openide.explorer.ExplorerManager; import org.openide.nodes.Node; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.AutoIngestJobStatus; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJobsNode.JobNode; @@ -37,6 +38,10 @@ import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.JobsSnaps final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerManager.Provider { private static final long serialVersionUID = 1L; + private static final int INITIAL_CASENAME_WIDTH = 170; + private static final int INITIAL_DATASOURCE_WIDTH = 270; + private static final int INITIAL_PRIORITIZED_WIDTH = 20; + private static final int INITIAL_STATUS_WIDTH = 20; private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; @@ -59,46 +64,76 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa * Set up the AutoIngestJobsPanel's so that its outlineView is displaying * the correct columns for the specified AutoIngestJobStatus */ + @Messages({"AutoIngestJobsPanel.waitNode.text=Please wait..."}) void customize() { - + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestJobsNode_caseName_text()); + int indexOfColumn; switch (status) { case PENDING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text()); + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_priority_text()); + if (indexOfColumn != -1) { + outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_PRIORITIZED_WIDTH); + } break; case RUNNING_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_hostName_text(), Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text()); - outline.setColumnSorted(0, true, 1); + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_caseName_text()); + if (indexOfColumn != -1) { + outline.setColumnSorted(indexOfColumn, true, 1); + } break; case COMPLETED_JOB: outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text()); - outline.setColumnSorted(3, false, 1); + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_jobCompleted_text()); + if (indexOfColumn != -1) { + outline.setColumnSorted(indexOfColumn, false, 1); + } + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_status_text()); + if (indexOfColumn != -1) { + outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_STATUS_WIDTH); + } break; default: } - ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AutoIngestJobsNode_caseName_text()); outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); outline.setRootVisible(false); - outline.getColumnModel().getColumn(0).setPreferredWidth(160); - outline.getColumnModel().getColumn(1).setPreferredWidth(260); + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_caseName_text()); + if (indexOfColumn != -1) { + outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_CASENAME_WIDTH); + } + indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_dataSource_text()); + if (indexOfColumn != -1) { + outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_DATASOURCE_WIDTH); + } if (null == explorerManager) { explorerManager = new ExplorerManager(); } outline.setRowSelectionAllowed(false); add(outlineView, java.awt.BorderLayout.CENTER); - EmptyNode emptyNode = new EmptyNode("Please wait..."); + EmptyNode emptyNode = new EmptyNode(Bundle.AutoIngestJobsPanel_waitNode_text()); explorerManager.setRootContext(emptyNode); } + private int getColumnIndexByName(String columnName) { + for (int index = 0; index < outline.getColumnModel().getColumnCount(); index++) { + if (outline.getColumnModel().getColumn(index).getHeaderValue().toString().equals(columnName)) { + return index; + } + } + return -1; + } + @Override public void setSize(Dimension d) { super.setSize(d); From 044932d8bcc1b034b667580a76082311d483d45a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 12 Apr 2018 12:23:12 -0400 Subject: [PATCH 27/64] Updated 'createFileIngestModule()' to check object type. --- .../ingestmodule/IngestModuleFactory.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java index 6ef03ae00d..2f732ac60f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModuleFactory.java @@ -68,7 +68,17 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter { @Override public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { - return new IngestModule((IngestSettings) settings); + if (settings instanceof IngestSettings) { + return new IngestModule((IngestSettings) settings); + } + /* + * Compatibility check for older versions. + */ + if (settings instanceof NoIngestModuleIngestJobSettings) { + return new IngestModule(new IngestSettings()); + } + + throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings"); } @Override From e51fdc1658de617330ad1a814e27d403a422db6e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 12 Apr 2018 12:25:47 -0400 Subject: [PATCH 28/64] 3610 add initial version of admin mode to enable context menu file is userdir/adminAccess --- .../autoingest/AutoIngestJobsNode.java | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java index 0e5e94159c..7edf074e1a 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsNode.java @@ -18,11 +18,13 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.io.File; import javax.swing.Action; import java.time.Instant; import java.util.ArrayList; import java.util.Date; import java.util.List; +import org.openide.modules.Places; import org.openide.nodes.AbstractNode; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -189,22 +191,27 @@ final class AutoIngestJobsNode extends AbstractNode { @Override public Action[] getActions(boolean context) { List actions = new ArrayList<>(); - switch (jobStatus) { - case PENDING_JOB: - actions.add(new PrioritizationAction.PrioritizeJobAction(autoIngestJob)); - actions.add(new PrioritizationAction.PrioritizeCaseAction(autoIngestJob)); - PrioritizationAction.DeprioritizeJobAction deprioritizeJobAction = new PrioritizationAction.DeprioritizeJobAction(autoIngestJob); - deprioritizeJobAction.setEnabled(autoIngestJob.getPriority() > 0); - actions.add(deprioritizeJobAction); - PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(autoIngestJob); - deprioritizeCaseAction.setEnabled(autoIngestJob.getPriority() > 0); - actions.add(deprioritizeCaseAction); - break; - case RUNNING_JOB: - break; - case COMPLETED_JOB: - break; - default: + //WJS-TODO make this a publically accessible setting like isAdminModeEnabled + //Or at minimum make the file name a static variable + File f = new File(Places.getUserDirectory().getAbsolutePath() + File.separator + "adminAccess"); + if (f.exists()) { + switch (jobStatus) { + case PENDING_JOB: + actions.add(new PrioritizationAction.PrioritizeJobAction(autoIngestJob)); + actions.add(new PrioritizationAction.PrioritizeCaseAction(autoIngestJob)); + PrioritizationAction.DeprioritizeJobAction deprioritizeJobAction = new PrioritizationAction.DeprioritizeJobAction(autoIngestJob); + deprioritizeJobAction.setEnabled(autoIngestJob.getPriority() > 0); + actions.add(deprioritizeJobAction); + PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(autoIngestJob); + deprioritizeCaseAction.setEnabled(autoIngestJob.getPriority() > 0); + actions.add(deprioritizeCaseAction); + break; + case RUNNING_JOB: + break; + case COMPLETED_JOB: + break; + default: + } } return actions.toArray(new Action[actions.size()]); } From 79ac8165f28a97ff82054261112d0ea659fe34cc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 12 Apr 2018 12:27:17 -0400 Subject: [PATCH 29/64] 3610 remove buttons which have context actions from aid2.0 --- .../autoingest/AutoIngestDashboard.form | 89 ++----------- .../autoingest/AutoIngestDashboard.java | 126 ++---------------- .../experimental/autoingest/Bundle.properties | 8 -- 3 files changed, 26 insertions(+), 197 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form index 0bdc79f34f..214254e032 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.form @@ -31,27 +31,24 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -80,11 +77,7 @@ - - - - @@ -188,34 +181,6 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -226,33 +191,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java index e5f150948d..fa5b9037d4 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestDashboard.java @@ -32,7 +32,6 @@ import java.util.concurrent.ConcurrentHashMap; import javax.swing.JPanel; import javax.swing.SwingWorker; import javax.swing.UIManager; -import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.ServicesMonitor; @@ -92,47 +91,16 @@ final class AutoIngestDashboard extends JPanel implements Observer { pendingJobsPanel.setSize(pendingScrollPane.getSize()); pendingScrollPane.add(pendingJobsPanel); pendingScrollPane.setViewportView(pendingJobsPanel); - pendingJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - if (e.getValueIsAdjusting()) { - return; - } - AutoIngestJob job = this.pendingJobsPanel.getSelectedAutoIngestJob(); - - boolean enablePrioritizeButtons = false; - boolean enableDeprioritizeButtons = false; - if (job != null) { - enablePrioritizeButtons = true; - enableDeprioritizeButtons = job.getPriority() > 0; - } - this.prioritizeJobButton.setEnabled(enablePrioritizeButtons); - this.prioritizeCaseButton.setEnabled(enablePrioritizeButtons); - this.deprioritizeJobButton.setEnabled(enableDeprioritizeButtons); - this.deprioritizeCaseButton.setEnabled(enableDeprioritizeButtons); - }); pendingJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_pendingTable_toolTipText()); runningJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobStatus.RUNNING_JOB); runningJobsPanel.setSize(runningScrollPane.getSize()); runningScrollPane.add(runningJobsPanel); runningScrollPane.setViewportView(runningJobsPanel); - runningJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - boolean enabled = false; - this.prioritizeJobButton.setEnabled(enabled); - this.prioritizeCaseButton.setEnabled(enabled); - this.deprioritizeJobButton.setEnabled(enabled); - this.deprioritizeCaseButton.setEnabled(enabled); - }); runningJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_runningTable_toolTipText()); completedJobsPanel = new AutoIngestJobsPanel(AutoIngestJobsNode.AutoIngestJobStatus.COMPLETED_JOB); completedJobsPanel.setSize(completedScrollPane.getSize()); completedScrollPane.add(completedJobsPanel); completedScrollPane.setViewportView(completedJobsPanel); - completedJobsPanel.addListSelectionListener((ListSelectionEvent e) -> { - boolean enabled = false; - this.prioritizeJobButton.setEnabled(enabled); - this.prioritizeCaseButton.setEnabled(enabled); - this.deprioritizeJobButton.setEnabled(enabled); - this.deprioritizeCaseButton.setEnabled(enabled); - }); completedJobsPanel.setToolTipText(Bundle.AutoIngestDashboard_completedTable_toolTipText()); /* * Must set this flag, otherwise pop up menus don't close properly. @@ -326,11 +294,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { refreshButton = new javax.swing.JButton(); lbServicesStatus = new javax.swing.JLabel(); tbServicesStatusMessage = new javax.swing.JTextField(); - prioritizeJobButton = new javax.swing.JButton(); - prioritizeCaseButton = new javax.swing.JButton(); clusterMetricsButton = new javax.swing.JButton(); - deprioritizeJobButton = new javax.swing.JButton(); - deprioritizeCaseButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N @@ -364,24 +328,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { tbServicesStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.text")); // NOI18N tbServicesStatusMessage.setBorder(null); - org.openide.awt.Mnemonics.setLocalizedText(prioritizeJobButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.prioritizeJobButton.text")); // NOI18N - prioritizeJobButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.prioritizeJobButton.toolTipText")); // NOI18N - prioritizeJobButton.setEnabled(false); - prioritizeJobButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - prioritizeJobButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(prioritizeCaseButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.prioritizeCaseButton.text")); // NOI18N - prioritizeCaseButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.prioritizeCaseButton.toolTipText")); // NOI18N - prioritizeCaseButton.setEnabled(false); - prioritizeCaseButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - prioritizeCaseButtonActionPerformed(evt); - } - }); - org.openide.awt.Mnemonics.setLocalizedText(clusterMetricsButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.clusterMetricsButton.text")); // NOI18N clusterMetricsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -389,24 +335,6 @@ final class AutoIngestDashboard extends JPanel implements Observer { } }); - org.openide.awt.Mnemonics.setLocalizedText(deprioritizeJobButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.deprioritizeJobButton.text")); // NOI18N - deprioritizeJobButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.deprioritizeJobButton.toolTipText")); // NOI18N - deprioritizeJobButton.setEnabled(false); - deprioritizeJobButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - deprioritizeJobButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(deprioritizeCaseButton, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.deprioritizeCaseButton.text")); // NOI18N - deprioritizeCaseButton.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.deprioritizeCaseButton.toolTipText")); // NOI18N - deprioritizeCaseButton.setEnabled(false); - deprioritizeCaseButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - deprioritizeCaseButtonActionPerformed(evt); - } - }); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -417,29 +345,24 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addComponent(pendingScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(runningScrollPane, javax.swing.GroupLayout.Alignment.LEADING) .addComponent(completedScrollPane, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(prioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deprioritizeJobButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(prioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deprioritizeCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 127, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(clusterMetricsButton)) - .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(lbServicesStatus) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE))) + .addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 861, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbCompleted, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lbRunning, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(refreshButton, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(clusterMetricsButton))) .addContainerGap()) ); - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {clusterMetricsButton, prioritizeCaseButton, prioritizeJobButton, refreshButton}); + layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {clusterMetricsButton, refreshButton}); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -463,11 +386,7 @@ final class AutoIngestDashboard extends JPanel implements Observer { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(refreshButton) - .addComponent(prioritizeJobButton) - .addComponent(prioritizeCaseButton) - .addComponent(clusterMetricsButton) - .addComponent(deprioritizeJobButton) - .addComponent(deprioritizeCaseButton)) + .addComponent(clusterMetricsButton)) .addContainerGap()) ); }// //GEN-END:initComponents @@ -485,38 +404,19 @@ final class AutoIngestDashboard extends JPanel implements Observer { setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); }//GEN-LAST:event_refreshButtonActionPerformed - private void prioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeCaseButtonActionPerformed - new PrioritizationAction.PrioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); - }//GEN-LAST:event_prioritizeCaseButtonActionPerformed - private void clusterMetricsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clusterMetricsButtonActionPerformed new AutoIngestMetricsDialog(this.getTopLevelAncestor()); }//GEN-LAST:event_clusterMetricsButtonActionPerformed - private void deprioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeJobButtonActionPerformed - new PrioritizationAction.DeprioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); - }//GEN-LAST:event_deprioritizeJobButtonActionPerformed - - private void deprioritizeCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deprioritizeCaseButtonActionPerformed - new PrioritizationAction.DeprioritizeCaseAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); - }//GEN-LAST:event_deprioritizeCaseButtonActionPerformed - - private void prioritizeJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prioritizeJobButtonActionPerformed - new PrioritizationAction.PrioritizeJobAction(pendingJobsPanel.getSelectedAutoIngestJob()).actionPerformed(evt); - }//GEN-LAST:event_prioritizeJobButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton clusterMetricsButton; private javax.swing.JScrollPane completedScrollPane; - private javax.swing.JButton deprioritizeCaseButton; - private javax.swing.JButton deprioritizeJobButton; private javax.swing.JButton jButton1; private javax.swing.JLabel lbCompleted; private javax.swing.JLabel lbPending; private javax.swing.JLabel lbRunning; private javax.swing.JLabel lbServicesStatus; private javax.swing.JScrollPane pendingScrollPane; - private javax.swing.JButton prioritizeCaseButton; - private javax.swing.JButton prioritizeJobButton; private javax.swing.JButton refreshButton; private javax.swing.JScrollPane runningScrollPane; private javax.swing.JTextField tbServicesStatusMessage; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index a9a500a5b9..6194815f69 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -219,10 +219,6 @@ FileExporterSettingsPanel.SaveTooltip_1=Save the current rule AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables AutoIngestDashboard.refreshButton.text=&Refresh AutoIngestDashboard.jButton1.text=jButton1 -AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the top of the Pending queue. -AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job -AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. -AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case AutoIngestMetricsDialog.reportTextArea.text= AutoIngestDashboard.clusterMetricsButton.text=Auto Ingest &Metrics AutoIngestMetricsDialog.metricsButton.text=Generate Metrics Report @@ -233,10 +229,6 @@ ArchiveFilePanel.browseButton.text=Browse ArchiveFilePanel.pathTextField.text= ArchiveFilePanel.errorLabel.text=Error Label AutoIngestMetricsDialog.startingDataLabel.text=Starting Date: -AutoIngestDashboard.deprioritizeJobButton.toolTipText=Move the selected job to the top of the Pending queue. -AutoIngestDashboard.deprioritizeJobButton.text=Deprioritize J&ob -AutoIngestDashboard.deprioritizeCaseButton.text=Deprioritize C&ase -AutoIngestDashboard.deprioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestControlPanel.bnDeprioritizeCase.text=Deprioritize Case AutoIngestControlPanel.bnDeprioritizeJob.text=Deprioritize Job AutoIngestControlPanel.bnPrioritizeCase.text=Prioritize Case From 5fd9dbd62101b9c168457c6842389239ebf10724 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 12 Apr 2018 12:53:38 -0400 Subject: [PATCH 30/64] 3709: 1st test for embedded files --- Core/build.xml | 1 + .../autopsy/ingest/EmbeddedFileTest.java | 189 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100755 Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java diff --git a/Core/build.xml b/Core/build.xml index 90b588bbc3..d3e04083f8 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -85,6 +85,7 @@ + diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java new file mode 100755 index 0000000000..b3380944a0 --- /dev/null +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -0,0 +1,189 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; +import junit.framework.Test; +import org.apache.commons.io.FileUtils; +import org.netbeans.junit.NbModuleSuite; +import org.netbeans.junit.NbTestCase; +import org.openide.util.Exceptions; +import org.python.icu.impl.Assert; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseDetails; +import org.sleuthkit.autopsy.casemodule.ImageDSProcessor; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; +import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; +import org.sleuthkit.autopsy.modules.embeddedfileextractor.EmbeddedFileExtractorModuleFactory; +import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory; +import org.sleuthkit.autopsy.testutils.DataSourceProcessorRunner; +import org.sleuthkit.autopsy.testutils.IngestJobRunner; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + +public class EmbeddedFileTest extends NbTestCase { + + private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "EmbeddedFileTest"); + private static final File CASE_DIR = new File(CASE_DIRECTORY_PATH.toString()); + private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"embedded.vhd"); + private static final int DEEP_FOLDER_COUNT = 25; + private static int deepFolderTested = 0; + + public static Test suite() { + NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(EmbeddedFileTest.class). + clusters(".*"). + enableModules(".*"); + return conf.suite(); + } + + public EmbeddedFileTest(String name) { + super(name); + } + + @Override + public void setUp() { + // Delete the test directory, if it exists + if (CASE_DIRECTORY_PATH.toFile().exists()) { + try { + FileUtils.deleteDirectory(CASE_DIRECTORY_PATH.toFile()); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + assertFalse("Unable to delete existing test directory", CASE_DIRECTORY_PATH.toFile().exists()); + + // Create the test directory + CASE_DIRECTORY_PATH.toFile().mkdirs(); + assertTrue("Unable to create test directory", CASE_DIRECTORY_PATH.toFile().exists()); + + try { + Case.createAsCurrentCase(Case.CaseType.SINGLE_USER_CASE, CASE_DIRECTORY_PATH.toString(), new CaseDetails("EmbeddedFileTest")); + } catch (CaseActionException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + assertTrue(CASE_DIR.exists()); + ImageDSProcessor dataSourceProcessor = new ImageDSProcessor(); + try { + DataSourceProcessorRunner.ProcessorCallback callBack = DataSourceProcessorRunner.runDataSourceProcessor(dataSourceProcessor, IMAGE_PATH); + List dataSourceContent = callBack.getDataSourceContent(); + assertEquals(1, dataSourceContent.size()); + List errorMessages = callBack.getErrorMessages(); + assertEquals(0, errorMessages.size()); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException | InterruptedException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + + } + } + + @Override + public void tearDown() { + try { + Case.closeCurrentCase(); + //Seems like we need some time to close the case. + try { + Thread.sleep(2000); + } catch (Exception ex) { + + } + + FileUtils.deleteDirectory(CASE_DIR); + } catch (CaseActionException | IOException ex) { + Exceptions.printStackTrace(ex); + } + assertFalse(CASE_DIR.exists()); + } + + public void testEncription() { + final int numOfFiles = 11; + try { + Case openCase = Case.getOpenCase(); + runIngestJob(openCase.getDataSources()); + + List results = openCase.getSleuthkitCase().findAllFilesWhere("parent_path LIKE '%password%'"); + assertEquals(numOfFiles, results.size()); + int passwdProtectedZips = 0; + int nonPasswdProcted = 0; + for (AbstractFile file : results) { + //.zip file has artifact TSK_ENCRYPTION_DETECTED + if (file.getNameExtension().equalsIgnoreCase("zip")) { + ArrayList artifacts = file.getAllArtifacts(); + for (BlackboardArtifact artifact : artifacts) { + assertEquals(1, artifacts.size()); + assertEquals(artifact.getArtifactTypeID(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED.getTypeID()); + passwdProtectedZips++; + } + } else { + assertTrue(file.getAllArtifacts().size() == 0); + nonPasswdProcted++; + } + + } + //Make sure 2 password prected zip files has been tested + assertEquals(2, passwdProtectedZips); + //No other files has artifact TSK_ENCRYPTION_DETECTED + assertEquals(numOfFiles - 2, nonPasswdProcted); + } catch (NoCurrentCaseException | TskCoreException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + + } + + private void runIngestJob(List datasources) { + IngestModuleTemplate embeddedTemplate = getIngestModuleTemplate(new EmbeddedFileExtractorModuleFactory()); + IngestModuleTemplate hashLookupTemplate = getIngestModuleTemplate(new HashLookupModuleFactory()); + + ArrayList templates = new ArrayList<>(); + templates.add(embeddedTemplate); + templates.add(hashLookupTemplate); + IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestFileFiltersTest.class.getCanonicalName(), IngestType.FILES_ONLY, templates); + try { + List errs = IngestJobRunner.runIngestJob(datasources, ingestJobSettings); + for (IngestModuleError err : errs) { + System.out.println(String.format("Error: %s: %s.", err.getModuleDisplayName(), err.toString())); + } + assertEquals(0, errs.size()); + } catch (InterruptedException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex); + } + } + + private IngestModuleTemplate getIngestModuleTemplate(IngestModuleFactoryAdapter factory) { + IngestModuleIngestJobSettings settings = factory.getDefaultIngestJobSettings(); + IngestModuleTemplate template = new IngestModuleTemplate(factory, settings); + template.setEnabled(true); + return template; + } +} From 79221c2f80af54d12774e87d15634affa5e0d5ec Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 12 Apr 2018 13:00:47 -0400 Subject: [PATCH 31/64] 3709: cleanup --- .../src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java index b3380944a0..be44a34c3c 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/ingest/EmbeddedFileTest.java @@ -54,9 +54,7 @@ public class EmbeddedFileTest extends NbTestCase { private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "EmbeddedFileTest"); private static final File CASE_DIR = new File(CASE_DIRECTORY_PATH.toString()); private final Path IMAGE_PATH = Paths.get(this.getDataDir().toString(),"embedded.vhd"); - private static final int DEEP_FOLDER_COUNT = 25; - private static int deepFolderTested = 0; - + public static Test suite() { NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(EmbeddedFileTest.class). clusters(".*"). @@ -152,7 +150,7 @@ public class EmbeddedFileTest extends NbTestCase { //Make sure 2 password prected zip files has been tested assertEquals(2, passwdProtectedZips); //No other files has artifact TSK_ENCRYPTION_DETECTED - assertEquals(numOfFiles - 2, nonPasswdProcted); + assertEquals(numOfFiles - passwdProtectedZips, nonPasswdProcted); } catch (NoCurrentCaseException | TskCoreException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex); From ab1c424e0d363929c81b35b80d33e0d98ae982f3 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 12 Apr 2018 15:13:41 -0400 Subject: [PATCH 32/64] 3610 change invalid index of -1 for columns to be a Static variable --- .../autoingest/AutoIngestJobsPanel.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java index 4cb237f1a8..6e72f91d17 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobsPanel.java @@ -42,6 +42,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa private static final int INITIAL_DATASOURCE_WIDTH = 270; private static final int INITIAL_PRIORITIZED_WIDTH = 20; private static final int INITIAL_STATUS_WIDTH = 20; + private static final int INVALID_INDEX = -1; private final org.openide.explorer.view.OutlineView outlineView; private final Outline outline; private ExplorerManager explorerManager; @@ -74,7 +75,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text()); indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_priority_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_PRIORITIZED_WIDTH); } break; @@ -84,7 +85,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stage_text(), Bundle.AutoIngestJobsNode_stageTime_text(), Bundle.AutoIngestJobsNode_stageTime_text()); indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_caseName_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.setColumnSorted(indexOfColumn, true, 1); } break; @@ -94,11 +95,11 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text()); indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_jobCompleted_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.setColumnSorted(indexOfColumn, false, 1); } indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_status_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_STATUS_WIDTH); } break; @@ -108,11 +109,11 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa outline.setRootVisible(false); indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_caseName_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_CASENAME_WIDTH); } indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_dataSource_text()); - if (indexOfColumn != -1) { + if (indexOfColumn != INVALID_INDEX) { outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_DATASOURCE_WIDTH); } if (null == explorerManager) { @@ -131,7 +132,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa return index; } } - return -1; + return INVALID_INDEX; } @Override From e36607acccc5772088132ffc6a8b9dff51db05bd Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Fri, 13 Apr 2018 08:20:02 -0400 Subject: [PATCH 33/64] Moved solr metrics further down. --- .../src/org/sleuthkit/autopsy/keywordsearch/Ingester.java | 2 -- .../src/org/sleuthkit/autopsy/keywordsearch/Server.java | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index b9c4541c7b..4e41a09aa9 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -237,9 +237,7 @@ class Ingester { try { //TODO: consider timeout thread, or vary socket timeout based on size of indexed content - TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk"); solrServer.addDocument(updateDoc); - EnterpriseHealthMonitor.submitTimingMetric(metric); uncommitedIngests = true; } catch (KeywordSearchModuleException | NoOpenCoreException ex) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index eea4d2914e..556eca08e4 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -710,7 +710,9 @@ public class Server { if (null == currentCore) { throw new NoOpenCoreException(); } + TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Index chunk"); currentCore.addDocument(doc); + EnterpriseHealthMonitor.submitTimingMetric(metric); } finally { currentCoreLock.readLock().unlock(); } @@ -775,9 +777,7 @@ public class Server { IndexingServerProperties properties = getMultiUserServerProperties(theCase.getCaseDirectory()); currentSolrServer = new HttpSolrServer("http://" + properties.getHost() + ":" + properties.getPort() + "/solr"); //NON-NLS } - TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check"); connectToSolrServer(currentSolrServer); - EnterpriseHealthMonitor.submitTimingMetric(metric); } catch (SolrServerException | IOException ex) { throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg", ex.getLocalizedMessage()), ex); @@ -1319,11 +1319,13 @@ public class Server { * @throws IOException */ void connectToSolrServer(HttpSolrServer solrServer) throws SolrServerException, IOException { + TimingMetric metric = EnterpriseHealthMonitor.getTimingMetric("Solr: Connectivity check"); CoreAdminRequest statusRequest = new CoreAdminRequest(); statusRequest.setCoreName( null ); statusRequest.setAction( CoreAdminParams.CoreAdminAction.STATUS ); statusRequest.setIndexInfoNeeded(false); statusRequest.process(solrServer); + EnterpriseHealthMonitor.submitTimingMetric(metric); } /** From c40149cb9d8ec0f8f113aeddb75a0f7a076120b3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 13 Apr 2018 10:28:54 -0400 Subject: [PATCH 34/64] 3709: update Google doc ID --- Core/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/build.xml b/Core/build.xml index d3e04083f8..b5b571d137 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -85,7 +85,7 @@ - + From 88c71b848891c4d792ef1f41c22aacaecb68f837 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 13 Apr 2018 11:28:55 -0400 Subject: [PATCH 35/64] Fixed File Metadata scroll bars. --- Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form | 5 +++-- Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form index b9cd3d0fdd..b175b6b512 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.form @@ -11,7 +11,7 @@ - + @@ -41,7 +41,8 @@ - + + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 060280ed08..1bfa05d5b8 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -59,9 +59,10 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { jScrollPane2 = new javax.swing.JScrollPane(); jTextPane1 = new javax.swing.JTextPane(); - setPreferredSize(new java.awt.Dimension(610, 52)); + setPreferredSize(new java.awt.Dimension(100, 52)); - jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); jScrollPane2.setPreferredSize(new java.awt.Dimension(610, 52)); jTextPane1.setEditable(false); From 4cd8615a141841f52d4f121ffd2a3ee7dec3b8ce Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 13 Apr 2018 11:33:39 -0400 Subject: [PATCH 36/64] Fixed Results scroll bars. --- .../DataContentViewerArtifact.form | 367 +++++++++--------- .../DataContentViewerArtifact.java | 35 +- 2 files changed, 212 insertions(+), 190 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form index d6bce85869..fc2e7d551d 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.form @@ -27,7 +27,7 @@ - + @@ -45,201 +45,214 @@ - + + - + + + + + - + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 48e84e6d79..b95af818a6 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -200,6 +200,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat rightClickMenu = new javax.swing.JPopupMenu(); copyMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); + jScrollPane1 = new javax.swing.JScrollPane(); jPanel1 = new javax.swing.JPanel(); totalPageLabel = new javax.swing.JLabel(); ofLabel = new javax.swing.JLabel(); @@ -208,8 +209,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat nextPageButton = new javax.swing.JButton(); pageLabel2 = new javax.swing.JLabel(); prevPageButton = new javax.swing.JButton(); - resultsTableScrollPane = new javax.swing.JScrollPane(); artifactLabel = new javax.swing.JLabel(); + resultsTableScrollPane = new javax.swing.JScrollPane(); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -217,7 +218,10 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerArtifact.class, "DataContentViewerArtifact.selectAllMenuItem.text")); // NOI18N rightClickMenu.add(selectAllMenuItem); - setPreferredSize(new java.awt.Dimension(622, 58)); + setPreferredSize(new java.awt.Dimension(100, 58)); + + jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); jPanel1.setPreferredSize(new java.awt.Dimension(620, 58)); @@ -264,9 +268,6 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat } }); - resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( @@ -286,8 +287,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(334, Short.MAX_VALUE)) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap(383, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap(280, Short.MAX_VALUE) @@ -306,24 +306,32 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE) - .addGap(0, 0, 0)) + .addContainerGap(35, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(artifactLabel) - .addGap(0, 401, Short.MAX_VALUE))) + .addGap(0, 58, Short.MAX_VALUE))) ); + jScrollPane1.setViewportView(jPanel1); + + resultsTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + resultsTableScrollPane.setPreferredSize(new java.awt.Dimension(620, 34)); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 622, Short.MAX_VALUE) + .addComponent(jScrollPane1) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(resultsTableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -346,6 +354,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private javax.swing.JMenuItem copyMenuItem; private javax.swing.JLabel currentPageLabel; private javax.swing.JPanel jPanel1; + private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton nextPageButton; private javax.swing.JLabel ofLabel; private javax.swing.JLabel pageLabel; From 1cda528898d758a3d39b92416583fba313922986 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 13 Apr 2018 11:35:20 -0400 Subject: [PATCH 37/64] Fixed Hex scroll bars. --- .../corecomponents/DataContentViewerHex.form | 454 +++++++++--------- .../corecomponents/DataContentViewerHex.java | 79 ++- 2 files changed, 260 insertions(+), 273 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form index 69f92968a3..745c862756 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.form @@ -27,7 +27,7 @@ - + @@ -45,261 +45,253 @@ - - + + - - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - - - - - - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java index 31888037b7..2b75990d68 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerHex.java @@ -62,15 +62,15 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont } private void customizeComponents() { - outputViewPane.setComponentPopupMenu(rightClickMenu); + outputTextArea.setComponentPopupMenu(rightClickMenu); ActionListener actList = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JMenuItem jmi = (JMenuItem) e.getSource(); if (jmi.equals(copyMenuItem)) { - outputViewPane.copy(); + outputTextArea.copy(); } else if (jmi.equals(selectAllMenuItem)) { - outputViewPane.selectAll(); + outputTextArea.selectAll(); } } }; @@ -90,6 +90,9 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont rightClickMenu = new javax.swing.JPopupMenu(); copyMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); + jScrollPane3 = new javax.swing.JScrollPane(); + outputTextArea = new javax.swing.JTextArea(); + jScrollPane2 = new javax.swing.JScrollPane(); hexViewerPanel = new javax.swing.JPanel(); totalPageLabel = new javax.swing.JLabel(); ofLabel = new javax.swing.JLabel(); @@ -102,14 +105,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont goToPageLabel = new javax.swing.JLabel(); goToOffsetLabel = new javax.swing.JLabel(); goToOffsetTextField = new javax.swing.JTextField(); - jScrollPane1 = new javax.swing.JScrollPane(); - outputViewPane = new JTextPane(){ - public boolean getScrollableTracksViewportWidth() { - return (getSize().width < 400); - }}; - this.outputViewPane.setBackground(new java.awt.Color(255, 255, 255)); // to make sure the background color is white - this.outputViewPane.requestFocusInWindow(); - this.outputViewPane.setCursor(Cursor.getDefaultCursor()); copyMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.copyMenuItem.text")); // NOI18N rightClickMenu.add(copyMenuItem); @@ -117,9 +112,18 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.selectAllMenuItem.text")); // NOI18N rightClickMenu.add(selectAllMenuItem); - setPreferredSize(new java.awt.Dimension(610, 58)); + setPreferredSize(new java.awt.Dimension(100, 58)); - hexViewerPanel.setPreferredSize(new java.awt.Dimension(610, 23)); + jScrollPane3.setPreferredSize(new java.awt.Dimension(300, 33)); + + outputTextArea.setEditable(false); + outputTextArea.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N + outputTextArea.setTabSize(0); + outputTextArea.setInheritsPopupMenu(true); + jScrollPane3.setViewportView(outputTextArea); + + jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.totalPageLabel.text_1")); // NOI18N @@ -210,7 +214,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addComponent(goToOffsetLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(goToOffsetTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(32, Short.MAX_VALUE)) ); hexViewerPanelLayout.setVerticalGroup( hexViewerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -231,31 +235,21 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont .addGap(0, 0, 0)) ); - jScrollPane1.setBackground(new java.awt.Color(255, 255, 255)); - jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - jScrollPane1.setPreferredSize(new java.awt.Dimension(610, 402)); - - outputViewPane.setEditable(false); - outputViewPane.setFont(new java.awt.Font("Courier New", 0, 11)); // NOI18N - outputViewPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR)); - outputViewPane.setMinimumSize(new java.awt.Dimension(600, 20)); - outputViewPane.setPreferredSize(new java.awt.Dimension(700, 400)); - jScrollPane1.setViewportView(outputViewPane); + jScrollPane2.setViewportView(hexViewerPanel); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hexViewerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 701, Short.MAX_VALUE) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE) + .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(hexViewerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE) - .addGap(0, 0, 0)) + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -305,16 +299,16 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont String userSelectedLine; try { // get the selected line. Extract the current hex offset location. - userSelectedLine = outputViewPane.getText().subSequence( - Utilities.getRowStart(outputViewPane, outputViewPane.getCaretPosition()), - Utilities.getRowEnd(outputViewPane, outputViewPane.getCaretPosition())) + userSelectedLine = outputTextArea.getText().subSequence( + Utilities.getRowStart(outputTextArea, outputTextArea.getCaretPosition()), + Utilities.getRowEnd(outputTextArea, outputTextArea.getCaretPosition())) .toString(); - // NOTE: This needs to change if the outputFormat of outputViewPane changes. + // NOTE: This needs to change if the outputFormat of outputTextArea changes. String hexForUserSelectedLine = userSelectedLine.substring(0, userSelectedLine.indexOf(":")); return Long.decode(hexForUserSelectedLine) + userInput; } catch (BadLocationException | StringIndexOutOfBoundsException | NumberFormatException ex) { - // thrown in case the caret location is out of the range of the outputViewPane. + // thrown in case the caret location is out of the range of the outputTextArea. return -1L; } } @@ -336,7 +330,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont if (offset >= 0) { setDataViewByOffset(offset); } else { - outputViewPane.setText(NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue")); + outputTextArea.setText(NbBundle.getMessage(DataContentViewerHex.class, "DataContentViewerHex.setDataView.invalidOffset.negativeOffsetValue")); } }//GEN-LAST:event_goToOffsetTextFieldActionPerformed @@ -348,10 +342,11 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont private javax.swing.JLabel goToPageLabel; private javax.swing.JTextField goToPageTextField; private javax.swing.JPanel hexViewerPanel; - private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JScrollPane jScrollPane3; private javax.swing.JButton nextPageButton; private javax.swing.JLabel ofLabel; - private javax.swing.JTextPane outputViewPane; + private javax.swing.JTextArea outputTextArea; private javax.swing.JLabel pageLabel; private javax.swing.JLabel pageLabel2; private javax.swing.JButton prevPageButton; @@ -434,12 +429,12 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont // set the output view if (errorText == null) { int showLength = bytesRead < pageLength ? bytesRead : (int) pageLength; - outputViewPane.setText(DataConversion.byteArrayToHex(data, showLength, offset)); + outputTextArea.setText(DataConversion.byteArrayToHex(data, showLength, offset)); } else { - outputViewPane.setText(errorText); + outputTextArea.setText(errorText); } - outputViewPane.setCaretPosition(0); + outputTextArea.setCaretPosition(0); this.setCursor(null); } @@ -488,7 +483,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont this.dataSource = null; currentPageLabel.setText(""); totalPageLabel.setText(""); - outputViewPane.setText(""); + outputTextArea.setText(""); setComponentsVisibility(false); // hides the components that not needed } @@ -541,7 +536,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont if (evt.isPopupTrigger()) { rightClickMenu.setLocation(evt.getLocationOnScreen()); rightClickMenu.setVisible(true); - copyMenuItem.setEnabled(outputViewPane.getSelectedText() != null); + copyMenuItem.setEnabled(outputTextArea.getSelectedText() != null); } else { rightClickMenu.setVisible(false); } From 380869b3e508cd64106dc17da9514c96d8295795 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 13 Apr 2018 11:40:30 -0400 Subject: [PATCH 38/64] Fixed Strings scroll bars. --- .../DataContentViewerString.form | 465 +++++++++--------- .../DataContentViewerString.java | 76 +-- 2 files changed, 273 insertions(+), 268 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.form index 20e77d395a..5a35bde9b5 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.form @@ -29,6 +29,9 @@ + + + @@ -45,258 +48,258 @@ - + + - + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java index c006a45aa0..ff48a678f2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerString.java @@ -100,12 +100,10 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC rightClickMenu = new javax.swing.JPopupMenu(); copyMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); - jPanel1 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); - outputViewPane = new JTextPane(){ - public boolean getScrollableTracksViewportWidth() { - return (getSize().width < 400); - }}; + outputViewPane = new javax.swing.JTextPane(); + jScrollPane2 = new javax.swing.JScrollPane(); + jPanel2 = new javax.swing.JPanel(); totalPageLabel = new javax.swing.JLabel(); ofLabel = new javax.swing.JLabel(); currentPageLabel = new javax.swing.JLabel(); @@ -125,10 +123,8 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC rightClickMenu.add(selectAllMenuItem); setMinimumSize(new java.awt.Dimension(5, 5)); + setPreferredSize(new java.awt.Dimension(100, 144)); - jPanel1.setPreferredSize(new java.awt.Dimension(640, 424)); - - jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); jScrollPane1.setPreferredSize(new java.awt.Dimension(640, 402)); outputViewPane.setEditable(false); @@ -136,6 +132,9 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC outputViewPane.setPreferredSize(new java.awt.Dimension(638, 400)); jScrollPane1.setViewportView(outputViewPane); + jScrollPane2.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + jScrollPane2.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + totalPageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.totalPageLabel.text_1")); // NOI18N ofLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.ofLabel.text_1")); // NOI18N @@ -199,11 +198,11 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC languageLabel.setText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.languageLabel.text")); // NOI18N languageLabel.setToolTipText(org.openide.util.NbBundle.getMessage(DataContentViewerString.class, "DataContentViewerString.languageLabel.toolTipText")); // NOI18N - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() + javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); + jPanel2.setLayout(jPanel2Layout); + jPanel2Layout.setHorizontalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() .addContainerGap() .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) @@ -225,39 +224,41 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC .addGap(33, 33, 33) .addComponent(languageLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(ofLabel) - .addComponent(totalPageLabel)) - .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(goToPageLabel) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(languageLabel))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 29, Short.MAX_VALUE)) + jPanel2Layout.setVerticalGroup( + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(pageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(currentPageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(ofLabel) + .addComponent(totalPageLabel)) + .addComponent(pageLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(goToPageLabel) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(goToPageTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(languageCombo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(languageLabel)) ); + jScrollPane2.setViewportView(jPanel2); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 728, Short.MAX_VALUE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 58, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 25, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -314,8 +315,9 @@ public class DataContentViewerString extends javax.swing.JPanel implements DataC private javax.swing.JLabel currentPageLabel; private javax.swing.JLabel goToPageLabel; private javax.swing.JTextField goToPageTextField; - private javax.swing.JPanel jPanel1; + private javax.swing.JPanel jPanel2; private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; private javax.swing.JComboBox