First cut at merging latest AIM

This commit is contained in:
Eugene Livis 2016-09-05 10:22:05 -04:00
parent efed6a333b
commit 885aba8daf
12 changed files with 768 additions and 548 deletions

View File

@ -28,8 +28,6 @@ import java.util.logging.Level;
* Utility for creating and checking for the existence of an automated ingest
* alert file. The purpose of the file is to put a marker in the case directory
* when an error or warning occurs in connection with an automated ingest job.
* If there is an error creating an alert file, it is logged to the auto ingest
* system log.
*/
final class AutoIngestAlertFile {
@ -54,7 +52,7 @@ final class AutoIngestAlertFile {
*
* @return True or false.
*/
static void create(Path caseDirectoryPath) {
static void create(Path caseDirectoryPath) throws AutoIngestAlertFileException {
try {
Files.createFile(caseDirectoryPath.resolve(ERROR_FILE_NAME));
} catch (FileAlreadyExistsException ignored) {
@ -67,15 +65,44 @@ final class AutoIngestAlertFile {
* for that case.
*/
if (!exists(caseDirectoryPath)) {
AutoIngestSystemLogger.getLogger().log(Level.SEVERE, String.format("Error creating automated ingest alert file in %s", caseDirectoryPath), ex);
throw new AutoIngestAlertFileException(String.format("Error creating automated ingest alert file in %s", caseDirectoryPath), ex);
}
}
}
/**
* Exception thrown when there is a problem creating an alert file.
*/
final static class AutoIngestAlertFileException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception to throw when there is a problem creating an
* alert file.
*
* @param message The exception message.
*/
private AutoIngestAlertFileException(String message) {
super(message);
}
/**
* Constructs an exception to throw when there is a problem creating an
* alert file.
*
* @param message The exception message.
* @param cause The cause of the exception, if it was an exception.
*/
private AutoIngestAlertFileException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* Prevents instantiation of this utility class.
*/
private AutoIngestAlertFile() {
}
}

View File

@ -24,23 +24,23 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
/**
* Event published when a case is deleted by the automated ingest manager.
*/
public final class AutoIngestCaseDeletedEvent extends AutopsyEvent implements Serializable {
@Immutable
final class AutoIngestCaseDeletedEvent extends AutopsyEvent implements Serializable {
private static final long serialVersionUID = 1L;
private final AutoIngestManager.CaseDeletionResult result;
private final String caseName;
private final String nodeName;
/**
* Constructs an event that is published when a case is deleted by the
* automated ingest manager.
*
* @param result The deletion result // RJCTODO: Get rid of logical
* deletion
* @param caseName The case name.
* @param nodeName The host name of the node that deleted the case.
*/
public AutoIngestCaseDeletedEvent(AutoIngestManager.CaseDeletionResult result, String nodeName) {
AutoIngestCaseDeletedEvent(String caseName, String nodeName) {
super(AutoIngestManager.Event.CASE_DELETED.toString(), null, null);
this.result = result;
this.caseName = caseName;
this.nodeName = nodeName;
}
@ -49,8 +49,8 @@ public final class AutoIngestCaseDeletedEvent extends AutopsyEvent implements Se
*
* @return
*/
public String getNodeName() {
return nodeName;
String getCaseName() {
return caseName;
}
/**
@ -58,8 +58,8 @@ public final class AutoIngestCaseDeletedEvent extends AutopsyEvent implements Se
*
* @return
*/
public AutoIngestManager.CaseDeletionResult getResult() {
return result;
String getNodeName() {
return nodeName;
}
}

View File

@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.events.AutopsyEvent;
* Event published when an automated ingest manager prioritizes all or part of a
* case.
*/
public final class AutoIngestCasePrioritizedEvent extends AutopsyEvent implements Serializable {
public final class AutoIngestCasePrioritizedEvent extends AutopsyEvent implements Serializable { // RJCTODO: Rename to AutoIngestPrioritizationEvent
private static final long serialVersionUID = 1L;
private final String caseName;

View File

@ -19,67 +19,62 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lbPending" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="pendingScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="bnPrioritizeCase" max="32767" attributes="0"/>
<Component id="bnPrioritizeJob" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="lbPending" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="pendingScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="bnPause" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="bnRefresh" linkSize="1" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="bnOptions" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="bnOpenLogDir" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="bnExit" linkSize="1" min="-2" pref="94" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="bnPrioritizeCase" min="-2" pref="117" max="-2" attributes="0"/>
<Component id="bnPrioritizeFolder" min="-2" pref="117" max="-2" attributes="0"/>
<Component id="runningScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
<Component id="completedScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="bnCancelJob" linkSize="1" pref="117" max="32767" attributes="0"/>
<Component id="bnShowProgress" linkSize="1" pref="116" max="32767" attributes="0"/>
<Component id="bnCancelModule" linkSize="1" alignment="0" pref="117" max="32767" attributes="0"/>
<Component id="bnDeleteCase" linkSize="1" alignment="0" pref="117" max="32767" attributes="0"/>
<Component id="bnShowCaseLog" max="32767" attributes="0"/>
<Component id="bnReprocessJob" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Component id="bnPause" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Component id="bnRefresh" linkSize="1" min="-2" pref="100" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Component id="bnOptions" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Component id="bnOpenLogDir" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
<Component id="bnExit" linkSize="1" min="-2" pref="94" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="runningScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
<Component id="completedScrollPane" min="-2" pref="920" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="bnCancelJob" linkSize="1" pref="117" max="32767" attributes="0"/>
<Component id="bnShowProgress" linkSize="1" pref="116" max="32767" attributes="0"/>
<Component id="bnCancelModule" linkSize="1" alignment="0" pref="117" max="32767" attributes="0"/>
<Component id="bnDeleteCase" linkSize="1" alignment="0" pref="117" max="32767" attributes="0"/>
<Component id="bnShowCaseLog" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lbStatus" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tbStatusMessage" min="-2" pref="861" max="-2" attributes="0"/>
</Group>
<Component id="lbCompleted" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbRunning" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lbStatus" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tbStatusMessage" min="-2" pref="861" max="-2" attributes="0"/>
</Group>
<Component id="lbCompleted" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbRunning" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="lbServicesStatus" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tbServicesStatusMessage" min="-2" pref="861" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="lbServicesStatus" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tbServicesStatusMessage" min="-2" pref="861" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -106,7 +101,7 @@
<EmptySpace min="-2" pref="82" max="-2" attributes="0"/>
<Component id="bnPrioritizeCase" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnPrioritizeFolder" min="-2" max="-2" attributes="0"/>
<Component id="bnPrioritizeJob" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
@ -127,9 +122,11 @@
</Group>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="102" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="68" max="-2" attributes="0"/>
<Component id="bnReprocessJob" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnDeleteCase" linkSize="2" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnShowCaseLog" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
@ -461,5 +458,15 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOpenLogDirActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="bnReprocessJob">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.bnReprocessJob.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnReprocessJobActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -54,10 +54,13 @@ import org.openide.LifecycleManager;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.core.ServicesMonitor;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog;
import org.sleuthkit.autopsy.experimental.AutoIngestManager.CaseDeletionResult;
import org.sleuthkit.autopsy.experimental.AutoIngestManager.JobsSnapshot;
import org.sleuthkit.autopsy.experimental.configuration.OptionsDialog;
/**
@ -91,7 +94,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280;
private static final String UPDATE_TASKS_THREAD_NAME = "AID-update-tasks-%d";
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
private static final Logger LOGGER = AutoIngestSystemLogger.getLogger();
private static final Logger SYS_LOGGER = AutoIngestSystemLogger.getLogger();
private static AutoIngestDashboard instance;
private final DefaultTableModel pendingTableModel;
private final DefaultTableModel runningTableModel;
@ -121,7 +124,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
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")),
IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.LocalJob"));
IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.LocalJob")),
MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath"));
private final String header;
@ -144,7 +148,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
STATUS.getColumnHeader(),
STAGE_TIME.getColumnHeader(),
CASE_DIRECTORY_PATH.getColumnHeader(),
IS_LOCAL_JOB.getColumnHeader()};
IS_LOCAL_JOB.getColumnHeader(),
MANIFEST_FILE_PATH.getColumnHeader()};
}
/**
@ -232,6 +237,29 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
return null;
}
/**
* Gets a status string for a given service.
*
* @param service The service to test.
*
* @return The status string.
*/
private String getServiceStatus(ServicesMonitor.Service service) {
String serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Unknown");
try {
ServicesMonitor servicesMonitor = ServicesMonitor.getInstance();
serviceStatus = servicesMonitor.getServiceStatus(service.toString());
if (serviceStatus.compareTo(ServicesMonitor.ServiceStatus.UP.toString()) == 0) {
serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up");
} else {
serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down");
}
} catch (ServicesMonitor.ServicesMonitorException ex) {
SYS_LOGGER.log(Level.SEVERE, String.format("Dashboard error getting service status for %s", service), ex);
}
return serviceStatus;
}
@Override
protected void done() {
tbServicesStatusMessage.setText(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message", caseDatabaseServerStatus, keywordSearchServiceStatus, keywordSearchServiceStatus, messagingStatus));
@ -249,30 +277,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
}
/**
* Gets a status string for a given service.
*
* @param service The service to test.
*
* @return up, down, or unknown
*/
private String getServiceStatus(ServicesMonitor.Service service) {
String serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Unknown");
try {
ServicesMonitor servicesMonitor = ServicesMonitor.getInstance();
serviceStatus = servicesMonitor.getServiceStatus(service.toString());
if (serviceStatus.compareTo(ServicesMonitor.ServiceStatus.UP.toString()) == 0) {
serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Up");
} else {
serviceStatus = NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.tbServicesStatusMessage.Message.Down");
}
} catch (ServicesMonitor.ServicesMonitorException ex) {
LOGGER.log(Level.SEVERE, String.format("Dashboard error getting service status for %s", service), ex);
}
return serviceStatus;
}
/**
* Sets up the JTable that presents a view of the
* Sets up the JTable that presents a view of the system-wide pending jobs
* queue.
*/
private void initPendingJobsTable() {
/*
@ -287,6 +293,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader()));
pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader()));
pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()));
pendingTable.removeColumn(pendingTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader()));
/*
* Set up a column to display the cases associated with the jobs.
@ -344,7 +351,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
}
/**
* Sets up the header and columns for the running auto ingest jobs table.
* Sets up the JTable that presents a view of the system-wide running jobs
* list.
*/
private void initRunningJobsTable() {
/*
@ -357,6 +365,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.STATUS.getColumnHeader()));
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader()));
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader()));
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader()));
/*
* Set up a column to display the cases associated with the jobs.
@ -438,8 +447,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
}
/**
* Sets up the header, columns, and selection listener for the completed
* auto ingest jobs table.
* Sets up the JTable that presents a view of the system-wide competed jobs
* list.
*/
private void initCompletedJobsTable() {
/*
@ -452,6 +461,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.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()));
/*
* Set up a column to display the cases associated with the jobs.
@ -558,11 +568,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
* @param enable Enable/disable the buttons.
*/
private void enablePendingTableButtons(Boolean enable) {
// RJCTODO: Restore prioritization feature
// bnPrioritizeCase.setEnabled(enable);
// bnPrioritizeFolder.setEnabled(enable);
bnPrioritizeCase.setEnabled(false);
bnPrioritizeFolder.setEnabled(false);
bnPrioritizeCase.setEnabled(enable);
bnPrioritizeJob.setEnabled(enable);
}
/**
@ -573,12 +580,12 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
private void startUp() {
/*
* Start up the auto ingest manager (AIM).
* Starts up the auto ingest manager (AIM).
*/
try {
manager.startUp();
} catch (AutoIngestManager.AutoIngestManagerStartupException ex) {
LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex);
SYS_LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex);
tbStatusMessage.setText(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupError"));
manager = null;
@ -594,20 +601,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
return;
}
/*
* Attempt to connect the AIM to any other auto ingest nodes (AINs) if
* this is a cluster.
*/
try {
manager.establishRemoteCommunications();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Dashboard error establishing remote communications for auto ingest", ex);
JOptionPane.showMessageDialog(this,
NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupWarning.Message"),
NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.AutoIngestStartupWarning.Title"),
JOptionPane.WARNING_MESSAGE);
}
/*
* Subscribe to services monitor events.
*/
@ -621,18 +614,10 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
manager.addObserver(this);
/*
* Populate the pending, running, and completed auto ingest tables.
* Populate the pending, running, and completed auto ingest job tables.
*/
updateExecutor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat(UPDATE_TASKS_THREAD_NAME).build());
updateExecutor.submit(new UpdateAllJobsTablesTask());
/*
* TODO (RC): This does not seem right, given that the AIM does its
* first image folder scan on start up. I think it could actually delay
* the population of the auto ingest job tables, since the table refresh
* and the scan both acquire the job lists manager. Does the AIM send an
* event after a scan? Need to check this.
*/
manager.scanInputDirsNow();
bnPause.setEnabled(true);
@ -743,7 +728,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
isPaused = true;
});
break;
case PAUSED_FOR_SYSTEM_ERROR: // RJCTODO: Consider making this more detailed again, probably not, too much maintenance and is iverkill
case PAUSED_FOR_SYSTEM_ERROR:
EventQueue.invokeLater(() -> {
tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.PauseDueToSystemError"));
bnOptions.setEnabled(true);
@ -777,9 +762,9 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
* running, and that the auto ingest manager will not actually pause until
* the current auto ingest job completes.
*
* @param buttonClicked Is this pause requests in response to a user gesture
* @param buttonClicked Is this pause request in response to a user gesture
* or a nofification from the auto ingest manager
* (AMI)?
* (AIM)?
*/
private void pause(boolean buttonClicked) {
/**
@ -1058,15 +1043,16 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
job.getNodeName(), // HOST_NAME
job.getManifest().getDateFileCreated(), // CREATED_TIME
job.getStageStartDate(), // STARTED_TIME
job.getStageStartDate(), // COMPLETED_TIME
job.getCompletedDate(), // COMPLETED_TIME
status.getDescription(), // ACTIVITY
(null != job.getCaseDirectoryPath()) ? AutoIngestAlertFile.exists(job.getCaseDirectoryPath()) : false, // STATUS // RJCTODO: awkward?
job.hasErrors(), // STATUS
((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH // RJCTODO: What about nulls?
job.getNodeName().equals(LOCAL_HOST_NAME)}); // IS_LOCAL_JOB // RJCTODO: move method that also does this
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
job.getNodeName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB
job.getManifest().getFilePath()}); // MANIFEST_FILE_PATH
}
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex); // NON-NLS // RJCTODO: Consider AID log
SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex);
}
}
@ -1100,10 +1086,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
bnShowCaseLog = new javax.swing.JButton();
tbStatusMessage = new javax.swing.JTextField();
lbStatus = new javax.swing.JLabel();
bnPrioritizeFolder = new javax.swing.JButton();
bnPrioritizeJob = new javax.swing.JButton();
lbServicesStatus = new javax.swing.JLabel();
tbServicesStatusMessage = new javax.swing.JTextField();
bnOpenLogDir = new javax.swing.JButton();
bnReprocessJob = new javax.swing.JButton();
pendingTable.setModel(pendingTableModel);
pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N
@ -1257,11 +1244,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
lbStatus.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(lbStatus, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.lbStatus.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeFolder, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeFolder.text")); // NOI18N
bnPrioritizeFolder.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeFolder.toolTipText")); // NOI18N
bnPrioritizeFolder.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(bnPrioritizeJob, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeJob.text")); // NOI18N
bnPrioritizeJob.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnPrioritizeJob.toolTipText")); // NOI18N
bnPrioritizeJob.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnPrioritizeFolderActionPerformed(evt);
bnPrioritizeJobActionPerformed(evt);
}
});
@ -1280,6 +1267,13 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
}
});
org.openide.awt.Mnemonics.setLocalizedText(bnReprocessJob, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.bnReprocessJob.text")); // NOI18N
bnReprocessJob.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnReprocessJobActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -1287,53 +1281,50 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bnPrioritizeCase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnPrioritizeJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lbPending, javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pendingScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(bnPrioritizeCase, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bnPrioritizeFolder, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(bnPause)
.addGap(18, 18, 18)
.addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(bnOptions)
.addGap(18, 18, 18)
.addComponent(bnOpenLogDir)
.addGap(18, 18, 18)
.addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(50, 50, 50)
.addComponent(bnPause)
.addGap(50, 50, 50)
.addComponent(bnRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(50, 50, 50)
.addComponent(bnOptions)
.addGap(50, 50, 50)
.addComponent(bnOpenLogDir)
.addGap(50, 50, 50)
.addComponent(bnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 94, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE)
.addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(layout.createSequentialGroup()
.addComponent(lbStatus)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(tbStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lbCompleted)
.addComponent(lbRunning))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(lbServicesStatus)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(tbServicesStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(completedScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 920, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(bnCancelJob, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnShowProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE)
.addComponent(bnCancelModule, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnDeleteCase, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addComponent(bnShowCaseLog, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnReprocessJob, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(layout.createSequentialGroup()
.addComponent(lbStatus)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(tbStatusMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 861, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lbCompleted)
.addComponent(lbRunning)
.addGroup(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)))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnCancelJob, bnCancelModule, bnDeleteCase, bnExit, bnOpenLogDir, bnOptions, bnPause, bnRefresh, bnShowProgress});
@ -1358,7 +1349,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
.addGap(82, 82, 82)
.addComponent(bnPrioritizeCase)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnPrioritizeFolder)))
.addComponent(bnPrioritizeJob)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lbRunning)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1374,9 +1365,11 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
.addComponent(runningScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(102, 102, 102)
.addGap(68, 68, 68)
.addComponent(bnReprocessJob)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnDeleteCase)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnShowCaseLog))
.addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -1419,55 +1412,47 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
* @param evt The button click event.
*/
private void bnDeleteCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDeleteCaseActionPerformed
// RJCTODO: Re-implement
// if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) {
// return;
// }
//
// String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal());
// Object[] options = {
// org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.Delete"),
// org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DoNotDelete")
// };
//
// // Add checkbox to allow user to delete images in input folder as well
// JCheckBox deleteInputChk = new JCheckBox("Delete input images for this case in shared input folder");
// Object[] msgContent = {org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DeleteAreYouSure") + "\"" + caseName + "\"?", deleteInputChk};
// int reply = JOptionPane.showOptionDialog(this,
// msgContent,
// org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmDeletionHeader"),
// JOptionPane.DEFAULT_OPTION,
// JOptionPane.WARNING_MESSAGE,
// null,
// options,
// options[JOptionPane.NO_OPTION]);
// if (reply == JOptionPane.YES_OPTION) {
// bnDeleteCase.setEnabled(false);
// bnShowCaseLog.setEnabled(false);
// if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) {
// String caseOutputFolderPath = completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_FOLDER.ordinal()).toString();
// String caseAutFilePath = completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal()).toString() + CaseMetadata.getFileExtension();
// completedTable.clearSelection();
// this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// AutoIngestManager.CaseDeletionResult deletionResult = manager.deleteCase(Paths.get(caseOutputFolderPath), deleteInputChk.isSelected(), caseAutFilePath);
// this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
// if (deletionResult.getCaseDeletionStatus() == AutoIngestManager.CaseDeletionResult.Status.FAILED) {
// JOptionPane.showMessageDialog(this, "Could not delete case " + caseName + " because it is in use",
// org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"), JOptionPane.INFORMATION_MESSAGE);
// } else if (deletionResult.getCaseDeletionStatus() == AutoIngestManager.CaseDeletionResult.Status.PARTIALLY_COMPLETED) {
// String str = "Deleted case \"" + caseName + "\", but not all files could be deleted.\nTo delete these files, stop automated ingest and delete \n"
// + caseOutputFolderPath + "\nand \n" + deletionResult.getCaseImageFolderPath() + "\nif present.";
// JOptionPane.showMessageDialog(this, str,
// org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"), JOptionPane.INFORMATION_MESSAGE);
// }
// /**
// * Need to update both the pending jobs table and the completed
// * jobs table since pending jobs for the deleted case are also
// * deleted.
// */
// updateExecutor.submit(new UpdateAllJobsTablesTask());
// }
// }
if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) {
return;
}
String caseName = (String) completedTable.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal());
Object[] options = {
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.Delete"),
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DoNotDelete")
};
Object[] msgContent = {org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.DeleteAreYouSure") + "\"" + caseName + "\"?"};
int reply = JOptionPane.showOptionDialog(this,
msgContent,
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "ConfirmationDialog.ConfirmDeletionHeader"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE,
null,
options,
options[JOptionPane.NO_OPTION]);
if (reply == JOptionPane.YES_OPTION) {
bnDeleteCase.setEnabled(false);
bnShowCaseLog.setEnabled(false);
if (completedTableModel.getRowCount() > 0 && completedTable.getSelectedRow() >= 0) {
Path caseDirectoryPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal());
completedTable.clearSelection();
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
CaseDeletionResult result = manager.deleteCase(caseName, caseDirectoryPath);
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if (CaseDeletionResult.FAILED == result) {
JOptionPane.showMessageDialog(this,
String.format("Could not delete case %s. It may be in in use.", caseName),
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"),
JOptionPane.INFORMATION_MESSAGE);
} else if (CaseDeletionResult.PARTIALLY_DELETED == result) {
JOptionPane.showMessageDialog(this,
String.format("Could not delete case %s. See system log for details.", caseName),
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.DeletionFailed"),
JOptionPane.INFORMATION_MESSAGE);
}
updateExecutor.submit(new UpdateAllJobsTablesTask());
}
}
}//GEN-LAST:event_bnDeleteCaseActionPerformed
/**
@ -1583,22 +1568,15 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
* @param evt The button click event.
*/
private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed
// RJCTODO: Re-implement
// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
// this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString();
// try {
// List<AutoIngestJob> prioritizedQueue = manager.prioritizeCase(caseName);
// refreshTable(prioritizedQueue, pendingTableModel, null);
// } catch (IOException ex) {
// logger.log(Level.SEVERE, String.format("Error while prioritizing case %s", caseName), ex);
// MessageNotifyUtil.Message.error("An error occurred while prioritizing the case.");
// } finally {
// pendingTable.clearSelection();
// enablePendingTableButtons(false);
// AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor());
// }
// }
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString();
List<AutoIngestJob> prioritizedQueue = manager.prioritizeCase(caseName);
refreshTable(prioritizedQueue, pendingTableModel, null);
pendingTable.clearSelection();
enablePendingTableButtons(false);
AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor());
}
}//GEN-LAST:event_bnPrioritizeCaseActionPerformed
/**
@ -1612,16 +1590,20 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
int selectedRow = completedTable.getSelectedRow();
if (selectedRow != -1) {
Path caseDirectoryPath = (Path) completedTableModel.getValueAt(selectedRow, JobsTableModelColumns.CASE_DIRECTORY_PATH.ordinal());
Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath);
if (pathToLog.toFile().exists()) {
Desktop.getDesktop().edit(pathToLog.toFile());
if (null != caseDirectoryPath) {
Path pathToLog = AutoIngestJobLogger.getLogPath(caseDirectoryPath);
if (pathToLog.toFile().exists()) {
Desktop.getDesktop().edit(pathToLog.toFile());
} else {
JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Message"),
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Title"), JOptionPane.ERROR_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Message"),
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.ShowLogFailed.Title"), JOptionPane.ERROR_MESSAGE);
MessageNotifyUtil.Message.warn("The case directory for this job has been deleted.");
}
}
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "Dashboard error attempting to display case auto ingest log", ex);
SYS_LOGGER.log(Level.SEVERE, "Dashboard error attempting to display case auto ingest log", ex);
Object[] options = {org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "DisplayLogDialog.okay")};
JOptionPane.showOptionDialog(this,
org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "DisplayLogDialog.cannotFindLog"),
@ -1634,25 +1616,17 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
}
}//GEN-LAST:event_bnShowCaseLogActionPerformed
private void bnPrioritizeFolderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeFolderActionPerformed
// RJCTODO: Re-implement
// if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
// this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString();
// String folderName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.DATA_SOURCE.ordinal())).toString();
// try {
// List<AutoIngestJob> prioritizedQueue = manager.prioritizeJob(caseName, folderName);
// refreshTable(prioritizedQueue, pendingTableModel, null);
// } catch (IOException ex) {
// logger.log(Level.SEVERE, String.format("Error while prioritizing folder %s", folderName), ex);
// MessageNotifyUtil.Message.error("An error occurred while prioritizing the folder.");
// } finally {
// pendingTable.clearSelection();
// enablePendingTableButtons(false);
// AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor());
// }
// }
}//GEN-LAST:event_bnPrioritizeFolderActionPerformed
private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()));
List<AutoIngestJob> prioritizedQueue = manager.prioritizeJob(manifestFilePath);
refreshTable(prioritizedQueue, pendingTableModel, null);
pendingTable.clearSelection();
enablePendingTableButtons(false);
AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor());
}
}//GEN-LAST:event_bnPrioritizeJobActionPerformed
private void bnOpenLogDirActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenLogDirActionPerformed
Path logDirPath = Paths.get(PlatformUtil.getUserDirectory().getAbsolutePath(), "var", "log");
@ -1661,11 +1635,24 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
Desktop.getDesktop().open(logDir);
} catch (IOException ex) {
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
String.format("Unable to open log directory %s:\n%s", logDirPath, ex.getLocalizedMessage()), // RJCTODO: Localize
String.format("Unable to open log directory %s:\n%s", logDirPath, ex.getLocalizedMessage()),
NotifyDescriptor.ERROR_MESSAGE));
}
}//GEN-LAST:event_bnOpenLogDirActionPerformed
private void bnReprocessJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnReprocessJobActionPerformed
if (completedTableModel.getRowCount() < 0 || completedTable.getSelectedRow() < 0) {
return;
}
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
Path manifestPath = (Path) completedTableModel.getValueAt(completedTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal());
JobsSnapshot jobsSnapshot = manager.reprocessJob(manifestPath);
refreshTable(jobsSnapshot.getCompletedJobs(), completedTableModel, null);
refreshTable(jobsSnapshot.getPendingJobs(), pendingTableModel, null);
refreshTable(jobsSnapshot.getRunningJobs(), runningTableModel, null);
AutoIngestDashboard.this.setCursor(Cursor.getDefaultCursor());
}//GEN-LAST:event_bnReprocessJobActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bnCancelJob;
private javax.swing.JButton bnCancelModule;
@ -1675,8 +1662,9 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
private javax.swing.JButton bnOptions;
private javax.swing.JButton bnPause;
private javax.swing.JButton bnPrioritizeCase;
private javax.swing.JButton bnPrioritizeFolder;
private javax.swing.JButton bnPrioritizeJob;
private javax.swing.JButton bnRefresh;
private javax.swing.JButton bnReprocessJob;
private javax.swing.JButton bnShowCaseLog;
private javax.swing.JButton bnShowProgress;
private javax.swing.JScrollPane completedScrollPane;

View File

@ -27,13 +27,13 @@ import java.util.Date;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.ingest.IngestJob;
/**
* An automated ingest job auto ingest jobs associated with a manifest file. A
* manifest file specifies a co-located data source and a case to which the data
* source is to be added.
* An automated ingest job for a manifest. The manifest specifies a co-located
* data source and a case to which the data source is to be added.
*/
@ThreadSafe
public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
@ -51,14 +51,38 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
@GuardedBy("this")
private Date stageStartDate;
@GuardedBy("this")
transient private DataSourceProcessor dataSourceProcessor;
@GuardedBy("this")
transient private IngestJob ingestJob;
@GuardedBy("this")
transient private boolean cancelled; // RJCTODO: Document
@GuardedBy("this")
transient private boolean completed; // RJCTODO: Document
@GuardedBy("this")
private Date completedDate;
@GuardedBy("this")
private boolean errorsOccurred;
/**
* RJCTODO
* Constructs an automated ingest job for a manifest. The manifest specifies
* a co-located data source and a case to which the data source is to be
* added.
*
* @param manifest
* @param manifest The manifest
* @param caseDirectoryPath The path to the case directory for the job, may
* be null.
* @param priority The priority of the job. The higher the number,
* the higher the priority.
* @param nodeName If the job is in progress, the node doing the
* processing, otherwise the locla host.
* @param stage The processing stage for display purposes.
* @param completedDate The date when the job was completed. Use the
* epoch (January 1, 1970, 00:00:00 GMT) to
* indicate the the job is not completed, i.e., new
* Date(0L).
*/
AutoIngestJob(Manifest manifest, Path caseDirectoryPath, int priority, String nodeName, Stage stage) {
// RJCTODO: The null case directory is error-prone and the nodeName is confusing.
AutoIngestJob(Manifest manifest, Path caseDirectoryPath, int priority, String nodeName, Stage stage, Date completedDate, boolean errorsOccurred) {
this.manifest = manifest;
if (null != caseDirectoryPath) {
this.caseDirectoryPath = caseDirectoryPath.toString();
@ -69,12 +93,14 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
this.nodeName = nodeName;
this.stage = stage;
this.stageStartDate = manifest.getDateFileCreated();
this.completedDate = completedDate;
this.errorsOccurred = errorsOccurred;
}
/**
* RJCTODO
* Gets the auto ingest jobmanifest.
*
* @return
* @return The manifest.
*/
Manifest getManifest() {
return this.manifest;
@ -86,6 +112,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
*
* @return True or false
*/
// RJCTODO: Use this or lose this
synchronized boolean hasCaseDirectoryPath() {
return (false == this.caseDirectoryPath.isEmpty());
}
@ -114,14 +141,21 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
}
}
/**
* Sets the priority of the job. A higher number indicates a higher
* priority.
*
* @param priority The priority.
*/
synchronized void setPriority(Integer priority) {
this.priority = priority;
}
/**
* RJCTODO
* Gets the priority of the job. A higher number indicates a higher
* priority.
*
* @return
* @return The priority.
*/
synchronized Integer getPriority() {
return this.priority;
@ -143,11 +177,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
* @param stateStartedDate
*/
synchronized void setStage(Stage newState, Date stateStartedDate) {
if (Stage.CANCELLED == this.stage && Stage.COMPLETED != newState) {
/**
* Do not overwrite canceling status with anything other than
* completed status.
*/
if (Stage.CANCELLING == this.stage && Stage.COMPLETED != newState) {
return;
}
this.stage = newState;
@ -214,10 +244,12 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
return new StageDetails(description, startDate);
}
synchronized void setDataSourceProcessor(DataSourceProcessor dataSourceProcessor) {
this.dataSourceProcessor = dataSourceProcessor;
}
/**
* RJCTODO
*
* @param ingestStatus
*/
// RJCTODO: Consider moving this class into AIM and making this private
synchronized void setIngestJob(IngestJob ingestJob) {
@ -226,8 +258,6 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
/**
* RJCTODO
*
* @return
*/
// RJCTODO: Consider moving this class into AIM and making this private.
// Or move the AID into a separate package. Or do not worry about it.
@ -235,6 +265,83 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
return this.ingestJob;
}
/**
* RJCTODO
*/
synchronized void cancel() {
setStage(Stage.CANCELLING);
cancelled = true;
errorsOccurred = true;
if (null != dataSourceProcessor) {
dataSourceProcessor.cancel();
}
if (null != ingestJob) {
ingestJob.cancel(IngestJob.CancellationReason.USER_CANCELLED);
}
}
/**
* RJCTODO
*/
synchronized boolean isCancelled() {
return cancelled;
}
/**
* RJCTODO
*/
synchronized void setCompleted() {
setStage(Stage.COMPLETED);
completed = true;
}
/**
* RJCTODO
*
* @return
*/
synchronized boolean isCompleted() {
return completed;
}
/**
* Sets the date the job was completed, with or without cancellation or
* errors.
*
* @param completedDate The completion date.
*/
synchronized void setCompletedDate(Date completedDate) {
this.completedDate = completedDate;
}
/**
* Gets the date the job was completed, with or without cancellation or
* errors.
*
* @return True or false.
*/
synchronized Date getCompletedDate() {
return completedDate; // RJCTODO: Consider returning null if == 0 (epoch)
}
/**
* Sets whether or not erros occurred during the processing of the job.
*
* @param errorsOccurred True or false;
*/
synchronized void setErrorsOccurred(boolean errorsOccurred) {
this.errorsOccurred = errorsOccurred;
}
/**
* Queries whether or not erros occurred during the processing of the job.
*
* @return True or false.
*/
synchronized boolean hasErrors() {
return this.errorsOccurred;
}
/**
* RJCTODO Gets name of the node associated with the job, possibly a remote
* hose if the job is in progress.
@ -309,30 +416,21 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
}
/**
* Custom comparator that sorts the pending list with prioritized cases
* first, then nonprioritized cases. Prioritized cases are last in, first
* out. Nonprioritized cases are first in, first out. Prioritized times are
* from the creation time of the "prioritized" state file. Non prioritized
* are from the folder creation time.
* Comparator that sorts auto ingest jobs by priority in descending order.
*/
public static class PriorityComparator implements Comparator<AutoIngestJob> {
/**
* RJCTODO
*
* @param o1
* @param o2
* @param job
* @param anotherJob
*
* @return
*/
@Override
public int compare(AutoIngestJob o1, AutoIngestJob o2) {
Integer result = o1.getPriority().compareTo(o2.getPriority());
if (0 != result) {
return result;
} else {
return o1.getManifest().getDateFileCreated().compareTo(o2.getManifest().getDateFileCreated());
}
public int compare(AutoIngestJob job, AutoIngestJob anotherJob) {
return -(job.getPriority().compareTo(anotherJob.getPriority()));
}
}
@ -364,6 +462,10 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
}
}
/**
* RJCTODO
*/
// RJCTODO: Combine this enum with StageDetails to make a single class.
enum Stage {
PENDING("Pending"),
@ -377,8 +479,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
ANALYZING_FILES("Analyzing files"),
EXPORTING_FILES("Exporting files"),
CANCELLING_MODULE("Cancelling module"),
CANCELLED("Cancelled"),
INTERRUPTED("Cancelled"),
CANCELLING("Cancelling"),
COMPLETED("Completed");
private final String displayText;

View File

@ -28,7 +28,6 @@ import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.experimental.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.experimental.coordinationservice.CoordinationService.Lock;
@ -59,6 +58,7 @@ final class AutoIngestJobLogger {
private static final String DATE_FORMAT_STRING = "yyyy/MM/dd HH:mm:ss";
private static final SimpleDateFormat logDateFormat = new SimpleDateFormat(DATE_FORMAT_STRING);
private final Path manifestPath;
private final String manifestFileName;
private final String dataSourceFileName;
private final Path caseDirectoryPath;
private final String hostName;
@ -73,7 +73,7 @@ final class AutoIngestJobLogger {
*/
INFO,
/**
* Qualifies a log message about an unexpected event or condition during
* Qualifies a log message about an unexpected event or condtion during
* automated ingest processing.
*/
WARNING,
@ -111,6 +111,7 @@ final class AutoIngestJobLogger {
*/
AutoIngestJobLogger(Path manifestPath, String dataSourceFileName, Path caseDirectoryPath) {
this.manifestPath = manifestPath;
manifestFileName = manifestPath.getFileName().toString();
this.dataSourceFileName = dataSourceFileName;
this.caseDirectoryPath = caseDirectoryPath;
hostName = NetworkUtils.getLocalHostName();
@ -119,151 +120,146 @@ final class AutoIngestJobLogger {
/**
* Logs the cancellation of an auto ingest job during processing.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logJobCancelled() throws InterruptedException {
void logJobCancelled() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.WARNING, "Auto ingest job cancelled during processing");
}
/**
* Logs the presence of a manifest file without a matching data source.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logMissingDataSource() throws InterruptedException {
log(MessageCategory.ERROR, "Data source file not found"); // RJCTODO: Check for this
void logMissingDataSource() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Data source file not found");
}
/**
* Logs an error identifying the type of a data source.
* Logs a failure to extract an archived data source.
*
* @param dataSource The data source.
* @param errorMessage The error.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file
* path.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceTypeIdError(String errorMessage) throws InterruptedException {
log(MessageCategory.ERROR, String.format("Error identifying data source type: %s", errorMessage));
void logFailedToExtractDataSource() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to extract data source from archive");
}
/**
* RJCTODO
* Logs a failure to parse a Cellebrite logical report data source.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logFailedToIdentifyDataSource() throws InterruptedException {
log(MessageCategory.ERROR, String.format("Failed to identifying data source type, cannot ingest"));
void logFailedToParseLogicalReportDataSource() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to parse Cellebrite logical report data source");
}
/**
* RJCTODO
* Logs a failure to identify an image data source as either a drive or
* phone image.
*
* @param dataSourceType
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceTypeId(String dataSourceType) throws InterruptedException {
log(MessageCategory.INFO, String.format("Identified data source as %s", dataSourceType));
void logFailedToIdentifyImageDataSource() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, String.format("Failed to identifying data source as drive or phone image"));
}
/**
* Logs cancellation of the addition of a data source to the case database.
*
* @param dataSourceType The data source type.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceProcessorCancelled(String dataSourceType) throws InterruptedException { // RJCTODO: Is this used now?
log(MessageCategory.WARNING, String.format("Cancelled adding data source to case as %s", dataSourceType));
void logDataSourceProcessorCancelled() throws AutoIngestJobLoggerException, InterruptedException { // RJCTODO: Is this used now?
log(MessageCategory.WARNING, "Cancelled adding data source to case");
}
/**
* Logs the addition of a data source to the case database.
*
* @param dataSourceType The data source type.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceAdded(String dataSourceType) throws InterruptedException {
log(MessageCategory.INFO, String.format("Added data source to case as %s", dataSourceType));
void logDataSourceAdded() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.INFO, "Added data source to case");
}
/**
* Logs a critical error reported by a data source processor when adding a
* data source to the case database.
* Logs an failure adding a data source to the case database.
*
* @param dataSourceType The data source type.
* @param errorMessage The error message.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceProcessorError(String dataSourceType, String errorMessage) throws InterruptedException {
log(MessageCategory.ERROR, String.format("Critical error adding data source to case as %s: %s", dataSourceType, errorMessage));
void logFailedToAddDataSource() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to add data source to case");
}
/**
* Logs a non-critical error reported by a data source processor when adding
* a data source to the case database.
* Logs failure of a data source to produce content.
*
* @param dataSourceType The data source type.
* @param errorMessage The error message.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logDataSourceProcessorWarning(String dataSourceType, String errorMessage) throws InterruptedException {
log(MessageCategory.WARNING, String.format("Critical error adding data source to case as %s: %s", dataSourceType, errorMessage));
void logNoDataSourceContent() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Data source failed to produce content");
}
/**
* Logs an error adding a data source to the case database.
* Logs failure to analyze a data source due to ingest job settings errors.
*
* @param dataSourceType The data source type.
* @param dataSource The data source.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logFailedToAddDataSource(String dataSourceType) throws InterruptedException { // RJCTODO: Why this and logDataSourceProcessorError? Bd handling of critical vs. non-critical?
log(MessageCategory.ERROR, String.format("Failed to add data source to case as %s", dataSourceType));
}
/**
* RJCTODO: Document and homogenize messages
*
* @param errors
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
*/
void logIngestJobSettingsErrors(List<String> errors) throws InterruptedException {
for (String error : errors) {
log(MessageCategory.ERROR, String.format("Settings error, analysis of data source by ingest modules not started: %s", error));
}
void logIngestJobSettingsErrors() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to analyze data source due to settings errors");
}
/**
* Logs failure to analyze a data source due to ingest module startup
* errors.
*
* @param errors The ingest module errors.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logIngestModuleStartupErrors(List<IngestModuleError> errors) throws InterruptedException {
for (IngestModuleError error : errors) {
log(MessageCategory.ERROR, String.format("Analysis of data source by ingest modules not started, %s startup error: %s", error.getModuleDisplayName(), error.getThrowable().getLocalizedMessage()));
}
void logIngestModuleStartupErrors() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to analyze data source due to ingest module startup errors");
}
/**
@ -272,21 +268,27 @@ final class AutoIngestJobLogger {
*
* @param ex The ingest manager exception.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logAnalysisStartupError(IngestManagerException ex) throws InterruptedException {
log(MessageCategory.ERROR, String.format("Analysis of data source by ingest modules not started: %s", ex.getLocalizedMessage()));
void logAnalysisStartupError() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Failed to analyze data source due to ingest job startup error");
}
/**
* Logs the completion of analysis of a data source by the ingest modules.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logAnalysisCompleted() throws InterruptedException {
log(MessageCategory.INFO, "Analysis of data source by ingest modules completed");
void logAnalysisCompleted() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.INFO, "Analysis of data source completed");
}
/**
@ -296,67 +298,79 @@ final class AutoIngestJobLogger {
* @param cancelledModuleName The display name of the cancelled ingest
* module.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logIngestModuleCancelled(String cancelledModuleName) throws InterruptedException {
void logIngestModuleCancelled(String cancelledModuleName) throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.WARNING, String.format("%s analysis of data source cancelled", cancelledModuleName));
}
/**
* Logs the cancellation of analysis of a data source by the ingest modules.
*
* @param reason The reason for cancellation.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logAnalysisCancelled(String reason) throws InterruptedException {
log(MessageCategory.WARNING, String.format("Analysis of data source by ingest modules cancelled: %s", reason));
void logAnalysisCancelled() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.WARNING, "Analysis of data source cancelled");
}
/**
* Logs that automated file export is not enabled.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logFileExportDisabled() throws InterruptedException {
void logFileExportDisabled() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.WARNING, "Automated file export is not enabled");
}
/**
* RJCTODO
* Logs completion of file export.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logFileExportCompleted() throws InterruptedException {
void logFileExportCompleted() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.INFO, "Automated file export completed");
}
/**
* RJCTODO
* Logs failure to complete file export.
*
* @param ex
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logFileExportError(Exception ex) throws InterruptedException {
log(MessageCategory.ERROR, String.format("Error exporting files: %s", ex.getMessage()));
void logFileExportError() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Error exporting files");
}
/**
* Logs discovery of a crashed auto ingest job for which recovery will be
* attempted.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logCrashRecoveryWithRetry() throws InterruptedException {
void logCrashRecoveryWithRetry() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Detected crash while processing, reprocessing");
}
@ -364,24 +378,16 @@ final class AutoIngestJobLogger {
* Logs discovery of a crashed auto ingest job for which recovery will not
* be attempted because the retry limit for the job has been reached.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
void logCrashRecoveryNoRetry() throws InterruptedException {
void logCrashRecoveryNoRetry() throws AutoIngestJobLoggerException, InterruptedException {
log(MessageCategory.ERROR, "Detected crash while processing, reached retry limit for processing");
}
/**
* Logs an unexpected runtime exception, e.g., an exception caught by the
* automated ingest job processing exception firewall.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
*/
void logErrorCondition(String message) throws InterruptedException {
log(MessageCategory.ERROR, message);
}
/**
* Writes a message to the case auto ingest log.
* <p>
@ -392,25 +398,55 @@ final class AutoIngestJobLogger {
* @param category The message category.
* @param message The message.
*
* @throws InterruptedException if interrupted while blocked waiting to
* acquire an exclusive lock on the log file.
* @throws AutoIngestJobLoggerException if there is an error writing the log
* message.
* @throws InterruptedException if interrupted while blocked waiting
* to acquire an exclusive lock on the
* log file.
*/
private void log(MessageCategory category, String message) throws InterruptedException {
String prefix = String.format("Failed to write case auto ingest message (\"%s\") for %s", message, manifestPath);
private void log(MessageCategory category, String message) throws AutoIngestJobLoggerException, InterruptedException {
try (Lock lock = CoordinationService.getInstance(CoordinationServiceNamespace.getRoot()).tryGetExclusiveLock(CoordinationService.CategoryNode.CASES, getLogPath(caseDirectoryPath).toString(), LOCK_TIME_OUT, LOCK_TIME_OUT_UNIT)) {
if (null != lock) {
File logFile = getLogPath(caseDirectoryPath).toFile();
try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(logFile, logFile.exists())), true)) {
writer.println(String.format("%s %s: %s\\%s: %-8s: %s", logDateFormat.format((Date.from(Instant.now()).getTime())), hostName, manifestPath, dataSourceFileName, category.toString(), message));
writer.println(String.format("%s %s: %s: %s: %-8s: %s", logDateFormat.format((Date.from(Instant.now()).getTime())), hostName, manifestFileName, dataSourceFileName, category.toString(), message));
} catch (IOException ex) {
AutoIngestSystemLogger.getLogger().log(Level.SEVERE, String.format("%s due to I/O error", prefix), ex);
throw new AutoIngestJobLoggerException(String.format("Failed to write case auto ingest log message (\"%s\") for %s", message, manifestPath), ex);
}
} else {
AutoIngestSystemLogger.getLogger().log(Level.SEVERE, String.format("%s due to lock timeout", prefix));
throw new AutoIngestJobLoggerException(String.format("Failed to write case auto ingest log message (\"%s\") for %s due to time out acquiring log lock", message, manifestPath));
}
} catch (CoordinationServiceException ex) {
AutoIngestSystemLogger.getLogger().log(Level.SEVERE, String.format("%s due to coordination service error", prefix), ex);
throw new AutoIngestJobLoggerException(String.format("Failed to write case auto ingest log message (\"%s\") for %s", message, manifestPath), ex);
}
}
/**
* Exception thrown when there is a problem writing a log message.
*/
final static class AutoIngestJobLoggerException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception to throw when there is a problem writing a
* log message.
*
* @param message The exception message.
*/
private AutoIngestJobLoggerException(String message) {
super(message);
}
/**
* Constructs an exception to throw when there is a problem writing a
* log message.
*
* @param message The exception message.
* @param cause The cause of the exception, if it was an exception.
*/
private AutoIngestJobLoggerException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -1,19 +1,20 @@
AutoIngestDashboard.bnRefresh.text=&Refresh
AutoIngestDashboard.lbCompleted.text=Completed
AutoIngestDashboard.lbRunning.text=Running
AutoIngestDashboard.lbPending.text=Pending
AutoIngestDashboard.lbCompleted.text=Completed Jobs
AutoIngestDashboard.lbRunning.text=Running Jobs
AutoIngestDashboard.lbPending.text=Pending Jobs
AutoIngestDashboard.bnCancelModule.text=Cancel &Module
AutoIngestDashboard.bnExit.text=&Exit
AutoIngestDashboard.bnOptions.text=&Options
AutoIngestDashboard.JobsTableModel.ColumnHeader.Case=Case
AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder=Data Source
AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName=Host Name
AutoIngestDashboard.JobsTableModel.ColumnHeader.CreatedTime=Created Time
AutoIngestDashboard.JobsTableModel.ColumnHeader.StartedTime=Started Time
AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime=Completed Time
AutoIngestDashboard.JobsTableModel.ColumnHeader.CreatedTime=Job Created
AutoIngestDashboard.JobsTableModel.ColumnHeader.StartedTime=Stage Started
AutoIngestDashboard.JobsTableModel.ColumnHeader.CompletedTime=Job Completed
AutoIngestDashboard.JobsTableModel.ColumnHeader.Stage=Stage
AutoIngestDashboard.JobsTableModel.ColumnHeader.Status=Status
AutoIngestDashboard.bnShowProgress.text=&Show Progress
AutoIngestDashboard.JobsTableModel.ColumnHeader.ManifestFilePath= Manifest File Path
AutoIngestDashboard.bnShowProgress.text=Ingest Progress
AutoIngestDashboard.bnResume.text=Resume
AutoIngestDashboard.bnPause.text=Pause
AutoIngestDashboard.bnPause.confirmHeader=Are you sure you want to pause?
@ -42,7 +43,7 @@ AutoIngestDashboard.ExitConsequences=This will cancel any currently running job
AutoIngestDashboard.ExitingStatus=Exiting...
AutoIngestDashboard.OK=OK
AutoIngestDashboard.Cancel=Cancel
AutoIngestDashboard.AutoIngestStartupFailed.Message=Failed to start automated ingest.\nPlease see application log for details.
AutoIngestDashboard.AutoIngestStartupFailed.Message=Failed to start automated ingest.\nPlease see auto ingest system log for details.
AutoIngestDashboard.AutoIngestStartupFailed.Title=Automated Ingest Error
AutoIngestDashboard.AutoIngestStartupError=Failed to start automated ingest. Verify Multi-user Settings.
AutoIngestDashboard.AutoIngestStartupWarning.Title=Automated Ingest Warning
@ -60,7 +61,7 @@ AutoIngestDashboard.tbServicesStatusMessage.Message=Case databases {0}, keyword
AutoIngestDashboard.tbServicesStatusMessage.Message.Up=up
AutoIngestDashboard.tbServicesStatusMessage.Message.Down=down
AutoIngestDashboard.tbServicesStatusMessage.Message.Unknown=unknown
AutoIngestDashboard.PauseDueToSystemError=Paused due to system error, please consult the auto ingest system log"
AutoIngestDashboard.PauseDueToSystemError=Paused due to system error, please consult the auto ingest system log
ConfirmationDialog.DoNotDelete=Do not delete
ConfirmationDialog.Delete=Permanently delete
ConfirmationDialog.DeleteAreYouSure=The entire case will be removed. Are you sure you want to delete case
@ -166,7 +167,7 @@ ReviewModeCasePanel.bnShowLog.text=&Show Log
AutoIngestDashboard.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue.
AutoIngestDashboard.bnPrioritizeCase.text=Prioriti&ze Case
AutoIngestDashboard.bnShowCaseLog.toolTipText=Display case log file for selected case
AutoIngestDashboard.bnShowCaseLog.text=Show &Log
AutoIngestDashboard.bnShowCaseLog.text=Show Case &Log
ReviewModeCasePanel.bnShowLog.toolTipText=Display case log file for selected case
CopyFilesPanel.bnCancelPendingJob.text=Ca&ncel
CopyFilesPanel.tbDestinationCase.text=
@ -197,8 +198,6 @@ CaseImportPanel.Complete=Complete
CaseImportPanel.Blank=
CaseImportPanel.DeleteWarning=Make sure no important files are in the case source directory
AutoIngestDashboard.lbStatus.text=Status:
AutoIngestDashboard.bnPrioritizeFolder.text=Prioritize &Folder
AutoIngestDashboard.bnPrioritizeFolder.toolTipText=Move this folder to the top of the Pending queue.
SingleUserCaseImporter.NonUniqueOutputFolder=Output folder not unique. Skipping
SingleUserCaseImporter.WillImport=Will import:
SingleUserCaseImporter.None=None
@ -283,4 +282,7 @@ FileExporterSettingsPanel.BrowseReportTooltip_1=Browse for the Reports Folder
FileExporterSettingsPanel.NewRuleTooltip_1=Clear the rule editor to begin a new rule
FileExporterSettingsPanel.DeleteTooltip_1=Delete the selected rule
FileExporterSettingsPanel.SaveTooltip_1=Save the current rule
AutoIngestDashboard.bnOpenLogDir.text=Open Log Directory
AutoIngestDashboard.bnOpenLogDir.text=Open System Logs Directory
AutoIngestDashboard.bnPrioritizeJob.text=Prioritize Job
AutoIngestDashboard.bnPrioritizeJob.toolTipText=Move this folder to the top of the Pending queue.
AutoIngestDashboard.bnReprocessJob.text=Reprocess Job

View File

@ -19,13 +19,13 @@
package org.sleuthkit.autopsy.experimental.autoingest;
/**
* RJCTODO
* Namespace elements for auto ingest coordination service nodes.
*/
final class CoordinationServiceNamespace {
static final String ROOT_COORD_SCV_NAMESPACE = "autopsy"; // RJCTODO: Move this elsewhere
private static final String ROOT = "autopsy";
static String getRoot() {
return ROOT_COORD_SCV_NAMESPACE;
return ROOT;
}
private CoordinationServiceNamespace() {

View File

@ -19,34 +19,35 @@
package org.sleuthkit.autopsy.experimental.autoingest;
import java.nio.ByteBuffer;
import java.util.Date;
/**
* RJCTODO
* A coordination service node data transfer object for an auto ingest job
* manifest. The data include: processing status, priority, the number of times
* the auto ingest job for the manifest has crashed during processing, and the
* date the auto ingest job for the manifest was completed.
*/
// RJCTODO: Consider making this encapsulate the locking as well, and to set the data as well
final class ManifestNodeData {
enum ProcessingStatus {
PENDING,
PROCESSING,
COMPLETED,
}
private static final int DEFAULT_PRIORITY = 0;
private final boolean nodeDataIsSet;
private final boolean coordSvcNodeDataWasSet;
private ProcessingStatus status;
private int priority;
private int numberOfCrashes;
private long completedDate;
private boolean errorsOccurred;
/**
* RJCTODO
* Constructs a coordination service node data data transfer object for an
* auto ingest manifest from the raw bytes obtained from the coordination
* service.
*
* @param nodeData
* @param nodeData The raw bytes received from the coordination service.
*/
ManifestNodeData(byte[] nodeData) {
ByteBuffer buffer = ByteBuffer.wrap(nodeData);
this.nodeDataIsSet = buffer.hasRemaining();
if (this.nodeDataIsSet) {
this.coordSvcNodeDataWasSet = buffer.hasRemaining();
if (this.coordSvcNodeDataWasSet) {
int rawStatus = buffer.getInt();
if (ProcessingStatus.PENDING.ordinal() == rawStatus) {
this.status = ProcessingStatus.PENDING;
@ -54,97 +55,183 @@ final class ManifestNodeData {
this.status = ProcessingStatus.PROCESSING;
} else if (ProcessingStatus.COMPLETED.ordinal() == rawStatus) {
this.status = ProcessingStatus.COMPLETED;
}else if (ProcessingStatus.DELETED.ordinal() == rawStatus) {
this.status = ProcessingStatus.DELETED;
}
this.priority = buffer.getInt();
this.numberOfCrashes = buffer.getInt();
this.completedDate = buffer.getLong();
int errorFlag = buffer.getInt();
this.errorsOccurred = (1 == errorFlag);
} else {
this.status = ProcessingStatus.PENDING;
this.priority = DEFAULT_PRIORITY;
this.numberOfCrashes = 0;
this.completedDate = 0L;
this.errorsOccurred = false;
}
}
/**
* RJCTODO
* Constructs a coordination service node data data transfer object for an
* auto ingest manifest from values provided by the auto ingest system.
*
* @param status The processing status of the manifest.
* @param priority The priority of the manifest.
* @param numberOfCrashes The number of times auto ingest jobs for the
* manifest have crashed during processing.
* @param completedDate The date the auto ingest job for the manifest was
* completed.
*/
ManifestNodeData(ProcessingStatus status, int priority, int numberOfCrashes) {
this.nodeDataIsSet = false;
ManifestNodeData(ProcessingStatus status, int priority, int numberOfCrashes, Date completedDate, boolean errorOccurred) {
this.coordSvcNodeDataWasSet = false;
this.status = status;
this.priority = priority;
this.numberOfCrashes = numberOfCrashes;
this.completedDate = completedDate.getTime();
this.errorsOccurred = errorOccurred;
}
/**
* RJCTODO
* Indicates whether or not the coordination service node data was set,
* i.e., this object was constructed from raw bytes from the ccordination
* service node for the manifest.
*
* @return
* @return True or false.
*/
boolean isSet() {
return this.nodeDataIsSet;
// RJCTODO: This is confusing, consider changing the API so that the use case is to
// check the length of the node data from the coordination service before
// constructing an instance of this object. That would be much more clear!
boolean coordSvcNodeDataWasSet() {
return this.coordSvcNodeDataWasSet;
}
/**
* RJCTODO
* Gets the processing status of the manifest
*
* @return
* @return The processing status of the manifest.
*/
ProcessingStatus getStatus() {
return this.status;
}
/**
* Sets the processing status of the manifest
*
* @param status
* @param status The processing status of the manifest.
*/
void setStatus(ProcessingStatus status) {
this.status = status;
}
/**
* Gets the priority of the manifest.
*
* @return
* @return The priority of the manifest.
*/
int getPriority() {
return this.priority;
}
/**
* Sets the priority of the manifest. A higher number indicates a higheer
* priority.
*
* @param priority
* @param priority The priority of the manifest.
*/
void setPriority(int priority) {
this.priority = priority;
}
/**
* RJCTODO
* Gets the number of times auto ingest jobs for the manifest have crashed
* during processing.
*
* @return
* @return The number of times auto ingest jobs for the manifest have
* crashed during processing.
*/
int getNumberOfCrashes() {
return this.numberOfCrashes;
}
/**
* RJCTODO
* Sets the number of times auto ingest jobs for the manifest have crashed
* during processing.
*
* @param attempts
* @param numberOfCrashes The number of times auto ingest jobs for the
* manifest have crashed during processing.
*/
void setNumberOfCrashes(int attempts) {
this.numberOfCrashes = attempts;
void setNumberOfCrashes(int numberOfCrashes) {
this.numberOfCrashes = numberOfCrashes;
}
/**
* RJCTODO
* Gets the date the auto ingest job for the manifest was completed.
*
* @return
* @return The date the auto ingest job for the manifest was completed. The
* epoch (January 1, 1970, 00:00:00 GMT) indicates the date is not
* set, i.e., Date.getTime() returns 0L.
*/
Date getCompletedDate() {
return new Date(this.completedDate);
}
/**
* Sets the date the auto ingest job for the manifest was completed.
*
* @param completedDate The date the auto ingest job for the manifest was
* completed. Use the epoch (January 1, 1970, 00:00:00
* GMT) to indicate the date is not set, i.e., new
* Date(0L).
*/
void setCompletedDate(Date completedDate) {
this.completedDate = completedDate.getTime();
}
/**
* Queries whether or not any errors occurred during the processing of the
* auto ingest job for the manifest.
*
* @return True or false.
*/
boolean getErrorsOccurred() {
return this.errorsOccurred;
}
/**
* Sets whether or not any errors occurred during the processing of the auto
* ingest job for the manifest.
*
* @param errorsOccurred True or false.
*/
void setErrorsOccurred(boolean errorsOccurred) {
this.errorsOccurred = errorsOccurred;
}
/**
* Gets the node data as raw bytes that can be sent to the coordination
* service.
*
* @return The manifest node data as a byte array.
*/
byte[] toArray() {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES * 3);
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES * 4 + Long.BYTES);
buffer.putInt(this.status.ordinal());
buffer.putInt(this.priority);
buffer.putInt(this.numberOfCrashes);
buffer.putLong(this.completedDate);
buffer.putInt(this.errorsOccurred ? 1 : 0);
return buffer.array();
}
/**
* Processing status for the auto ingest job for the manifest.
*/
enum ProcessingStatus {
PENDING,
PROCESSING,
COMPLETED,
DELETED
}
}

View File

@ -28,11 +28,9 @@ import java.util.Collections;
import java.util.List;
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.coreutils.Logger;
final class PathUtils {
private static final Logger logger = Logger.getLogger(PathUtils.class.getName());
private static final List<String> CASE_METADATA_FILE_EXTS = Arrays.asList(new String[]{CaseMetadata.getFileExtension()});
private static final GeneralFilter caseMetadataFileFilter = new GeneralFilter(CASE_METADATA_FILE_EXTS, "Autopsy Case File");
@ -71,7 +69,7 @@ final class PathUtils {
*
* @return A list of the output case folder paths.
*/
static List<Path> findCaseFolders(Path folderToSearch) {
static List<Path> findCaseFolders(Path folderToSearch) { // RJCTODO: Rename
File searchFolder = new File(folderToSearch.toString());
if (!searchFolder.isDirectory()) {
return Collections.emptyList();
@ -112,32 +110,6 @@ final class PathUtils {
return caseDataFiles.length != 0;
}
/**
* Extracts the path to the case images folder path from an image folder
* path.
*
* @param rootImageFoldersPath The root image folders path.
* @param imageFolderPath The image folder path.
*
* @return The root input folder path for a case.
*/
static Path caseImagesPathFromImageFolderPath(Path rootImageFoldersPath, Path imageFolderPath) {
return rootImageFoldersPath.resolve(imageFolderPath.subpath(0, rootImageFoldersPath.getNameCount() + 1).getFileName());
}
/**
* Extracts the case name from an image folder path.
*
* @param rootImageFoldersPath The root image folders path.
* @param imageFolderPath The image folder path.
*
* @return The case name.
*/
static String caseNameFromImageFolderPath(Path rootImageFoldersPath, Path imageFolderPath) {
Path caseImagesPath = PathUtils.caseImagesPathFromImageFolderPath(rootImageFoldersPath, imageFolderPath);
return caseImagesPath.getFileName().toString();
}
/**
* Extracts the case name from a case folder path.
*
@ -163,7 +135,7 @@ final class PathUtils {
*
* @return A case folder path with a time stamp suffix.
*/
static Path createCaseFolderPath(Path caseFoldersPath, String caseName) {
static Path createCaseFolderPath(Path caseFoldersPath, String caseName) { // RJCTODO: Rename
String folderName = caseName + "_" + TimeStampUtils.createTimeStamp();
return Paths.get(caseFoldersPath.toString(), folderName);
}

View File

@ -61,8 +61,8 @@ public final class ReviewModeCasePanel extends JPanel {
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 = 60;
private static final int MILLISECONDS_TO_WAIT_BEFORE_STARTING = 500;
private static final int MILLISECONDS_TO_WAIT_BETWEEN_UPDATES = 30000;
private static final int MILLISECONDS_TO_WAIT_BEFORE_STARTING = 500; // RJCTODO: Shorten name
private static final int MILLISECONDS_TO_WAIT_BETWEEN_UPDATES = 30000; // RJCTODO: Shorten name
private ScheduledThreadPoolExecutor casesTableRefreshExecutor;
/*
@ -84,7 +84,7 @@ public final class ReviewModeCasePanel extends JPanel {
CREATEDTIME,
COMPLETEDTIME,
STATUS_ICON,
OUTPUTFOLDER
OUTPUTFOLDER // RJCTODO: Change name
}
private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER};
private DefaultTableModel caseTableModel;
@ -325,7 +325,7 @@ public final class ReviewModeCasePanel extends JPanel {
autoIngestCase.getCaseName(),
autoIngestCase.getCreationDate(),
autoIngestCase.getLastAccessedDate(),
autoIngestCase.getStatus(),
(AutoIngestCase.CaseStatus.OK != autoIngestCase.getStatus()),
autoIngestCase.getCaseDirectoryPath().toString()});
}
}