@@ -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);
}
}
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
index d6617edb51..1880cef304 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
@@ -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
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CoordinationServiceNamespace.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CoordinationServiceNamespace.java
index 9de347eafd..1b1c4a1227 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CoordinationServiceNamespace.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/CoordinationServiceNamespace.java
@@ -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() {
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ManifestNodeData.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ManifestNodeData.java
index 67ef803136..e4e272edd3 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ManifestNodeData.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ManifestNodeData.java
@@ -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
+ }
+
}
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
index 7752e4d1dc..622912f95a 100644
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java
@@ -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