mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Merge branch 'sleuthkit:develop' into develop
This commit is contained in:
commit
c4420b6c91
@ -26,20 +26,22 @@ import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.NodeResults;
|
||||
import org.sleuthkit.autopsy.contentviewers.analysisresults.AnalysisResultsViewModel.ResultDisplayAttributes;
|
||||
import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerHtmlStyles;
|
||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||
import org.sleuthkit.datamodel.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
|
||||
/**
|
||||
* Displays a list of analysis results in a panel.
|
||||
*/
|
||||
public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
private static final String EMPTY_HTML = "<html><head></head><body></body></html>";
|
||||
|
||||
// Anchors are inserted into the navigation so that the viewer can navigate to a selection.
|
||||
@ -80,27 +82,18 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
*
|
||||
* @param nodeResults The analysis results data to display.
|
||||
*/
|
||||
@NbBundle.Messages("AnalysisResultsContentPanel_aggregateScore_displayKey=Aggregate Score")
|
||||
void displayResults(NodeResults nodeResults) {
|
||||
Document document = Jsoup.parse(EMPTY_HTML);
|
||||
Element body = document.getElementsByTag("body").first();
|
||||
|
||||
// if there is an aggregate score, append a section with the value
|
||||
Optional<Score> aggregateScore = nodeResults.getAggregateScore();
|
||||
if (aggregateScore.isPresent()) {
|
||||
appendSection(body,
|
||||
MessageFormat.format("{0}: {1}",
|
||||
Bundle.AnalysisResultsContentPanel_aggregateScore_displayKey(),
|
||||
aggregateScore.get().getSignificance().getDisplayName()),
|
||||
Optional.empty());
|
||||
}
|
||||
Optional<Element> panelHeader = appendPanelHeader(body, nodeResults.getContent(), nodeResults.getAggregateScore());
|
||||
|
||||
// for each analysis result item, display the data.
|
||||
List<ResultDisplayAttributes> displayAttributes = nodeResults.getAnalysisResults();
|
||||
for (int idx = 0; idx < displayAttributes.size(); idx++) {
|
||||
AnalysisResultsViewModel.ResultDisplayAttributes resultAttrs = displayAttributes.get(idx);
|
||||
Element sectionDiv = appendResult(body, idx, resultAttrs);
|
||||
if (idx > 0 || aggregateScore.isPresent()) {
|
||||
if (idx > 0 || panelHeader.isPresent()) {
|
||||
sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName());
|
||||
}
|
||||
}
|
||||
@ -119,6 +112,48 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the header to the panel.
|
||||
*
|
||||
* @param parent The parent html element.
|
||||
* @param content The content whose name will be added if present.
|
||||
* @param score The aggregate score whose significance will be added if
|
||||
* present.
|
||||
*
|
||||
* @return The html element.
|
||||
*/
|
||||
@Messages({
|
||||
"AnalysisResultsContentPanel_aggregateScore_displayKey=Aggregate Score",
|
||||
"AnalysisResultsContentPanel_content_displayKey=Item"
|
||||
})
|
||||
private Optional<Element> appendPanelHeader(Element parent, Optional<Content> content, Optional<Score> score) {
|
||||
if (!content.isPresent() || !score.isPresent()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Element container = parent.appendElement("div");
|
||||
|
||||
// if there is content append the name
|
||||
content.ifPresent((c) -> {
|
||||
container.appendElement("p")
|
||||
.attr("class", ContentViewerHtmlStyles.getTextClassName())
|
||||
.text(MessageFormat.format("{0}: {1}",
|
||||
Bundle.AnalysisResultsContentPanel_content_displayKey(),
|
||||
c.getName()));
|
||||
});
|
||||
|
||||
// if there is an aggregate score, append the value
|
||||
score.ifPresent((s) -> {
|
||||
container.appendElement("p")
|
||||
.attr("class", ContentViewerHtmlStyles.getTextClassName())
|
||||
.text(MessageFormat.format("{0}: {1}",
|
||||
Bundle.AnalysisResultsContentPanel_aggregateScore_displayKey(),
|
||||
s.getSignificance().getDisplayName()));
|
||||
});
|
||||
|
||||
return Optional.ofNullable(container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the anchor id to use with the analysis result (based on the id).
|
||||
*
|
||||
@ -151,7 +186,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
// create a table
|
||||
Element table = sectionDiv.appendElement("table");
|
||||
table.attr("class", ContentViewerHtmlStyles.getIndentedClassName());
|
||||
|
||||
|
||||
Element tableBody = table.appendElement("tbody");
|
||||
|
||||
// append a row for each item
|
||||
@ -160,7 +195,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
String keyString = keyVal.getKey() == null ? "" : keyVal.getKey() + ":";
|
||||
Element keyTd = row.appendElement("td")
|
||||
.attr("class", ContentViewerHtmlStyles.getTextClassName());
|
||||
|
||||
|
||||
keyTd.appendElement("span")
|
||||
.text(keyString)
|
||||
.attr("class", ContentViewerHtmlStyles.getKeyColumnClassName());
|
||||
@ -170,7 +205,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
.text(valueString)
|
||||
.attr("class", ContentViewerHtmlStyles.getTextClassName());
|
||||
}
|
||||
|
||||
|
||||
return sectionDiv;
|
||||
}
|
||||
|
||||
@ -199,7 +234,7 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel {
|
||||
header = (anchorEl == null)
|
||||
? sectionDiv.appendElement("h1")
|
||||
: anchorEl.appendElement("h1");
|
||||
|
||||
|
||||
header.text(headerText);
|
||||
header.attr("class", ContentViewerHtmlStyles.getHeaderClassName());
|
||||
header.attr("style", "display: inline-block");
|
||||
|
@ -94,6 +94,7 @@ public class AnalysisResultsViewModel {
|
||||
private final List<ResultDisplayAttributes> analysisResults;
|
||||
private final Optional<AnalysisResult> selectedResult;
|
||||
private final Optional<Score> aggregateScore;
|
||||
private final Optional<Content> content;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -102,11 +103,13 @@ public class AnalysisResultsViewModel {
|
||||
* @param selectedResult The selected analysis result or empty if none
|
||||
* selected.
|
||||
* @param aggregateScore The aggregate score or empty if no score.
|
||||
* @param content The content associated with these results.
|
||||
*/
|
||||
NodeResults(List<ResultDisplayAttributes> analysisResults, Optional<AnalysisResult> selectedResult, Optional<Score> aggregateScore) {
|
||||
NodeResults(List<ResultDisplayAttributes> analysisResults, Optional<AnalysisResult> selectedResult, Optional<Score> aggregateScore, Optional<Content> content) {
|
||||
this.analysisResults = analysisResults;
|
||||
this.selectedResult = selectedResult;
|
||||
this.aggregateScore = aggregateScore;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,6 +138,17 @@ public class AnalysisResultsViewModel {
|
||||
Optional<Score> getAggregateScore() {
|
||||
return aggregateScore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content associated with these results or empty if not
|
||||
* present.
|
||||
*
|
||||
* @return The content associated with these results or empty if not
|
||||
* present.
|
||||
*/
|
||||
Optional<Content> getContent() {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,10 +235,11 @@ public class AnalysisResultsViewModel {
|
||||
*/
|
||||
NodeResults getAnalysisResults(Node node) {
|
||||
if (node == null) {
|
||||
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty());
|
||||
return new NodeResults(Collections.emptyList(), Optional.empty(), Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
Optional<Score> aggregateScore = Optional.empty();
|
||||
Optional<Content> nodeContent = Optional.empty();
|
||||
// maps id of analysis result to analysis result to prevent duplication
|
||||
Map<Long, AnalysisResult> allAnalysisResults = new HashMap<>();
|
||||
Optional<AnalysisResult> selectedResult = Optional.empty();
|
||||
@ -236,6 +251,8 @@ public class AnalysisResultsViewModel {
|
||||
}
|
||||
|
||||
try {
|
||||
nodeContent = Optional.of(content);
|
||||
|
||||
// get the aggregate score of that content
|
||||
aggregateScore = Optional.ofNullable(content.getAggregateScore());
|
||||
|
||||
@ -273,6 +290,6 @@ public class AnalysisResultsViewModel {
|
||||
// get view model representation
|
||||
List<ResultDisplayAttributes> displayAttributes = getOrderedDisplayAttributes(allAnalysisResults.values());
|
||||
|
||||
return new NodeResults(displayAttributes, selectedResult, aggregateScore);
|
||||
return new NodeResults(displayAttributes, selectedResult, aggregateScore, nodeContent);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015-2019 Basis Technology Corp.
|
||||
* Copyright 2015-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearchservice;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||
@ -105,5 +106,14 @@ public interface KeywordSearchService extends Closeable {
|
||||
* @throws KeywordSearchServiceException if unable to delete.
|
||||
*/
|
||||
void deleteDataSource(Long dataSourceId) throws KeywordSearchServiceException;
|
||||
|
||||
/**
|
||||
* A flag to enable or disable OCR on all future text indexing.
|
||||
*
|
||||
* @param state Boolean flag to enable/disable OCR. Set to True to enable
|
||||
* OCR, or False to disable it.
|
||||
*/
|
||||
@Beta
|
||||
void changeOcrState(boolean state);
|
||||
|
||||
}
|
||||
|
@ -157,6 +157,102 @@ final class AutoIngestAdminActions {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"AutoIngestAdminActions.enableOCR.title=Enable OCR For This Case",
|
||||
"AutoIngestAdminActions.enableOCR.error=Failed to enable OCR for case \"%s\"."})
|
||||
static final class EnableOCR extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final AutoIngestJob job;
|
||||
|
||||
EnableOCR(AutoIngestJob job) {
|
||||
super(Bundle.AutoIngestAdminActions_enableOCR_title());
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
if (job == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(AutoIngestDashboardTopComponent.PREFERRED_ID);
|
||||
if (tc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoIngestDashboard dashboard = tc.getAutoIngestDashboard();
|
||||
if (dashboard != null) {
|
||||
dashboard.getPendingJobsPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EventQueue.invokeLater(() -> {
|
||||
try {
|
||||
dashboard.getMonitor().changeOcrStateForCase(job.getManifest().getCaseName(), true);
|
||||
dashboard.getPendingJobsPanel().refresh(new AutoIngestNodeRefreshEvents.RefreshCaseEvent(dashboard.getMonitor(), job.getManifest().getCaseName()));
|
||||
} catch (AutoIngestMonitor.AutoIngestMonitorException ex) {
|
||||
String errorMessage = String.format(Bundle.AutoIngestAdminActions_enableOCR_error(), job.getManifest().getCaseName());
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
MessageNotifyUtil.Message.error(errorMessage);
|
||||
} finally {
|
||||
dashboard.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"AutoIngestAdminActions.disableOCR.title=Disable OCR For This Case",
|
||||
"AutoIngestAdminActions.disableOCR.error=Failed to disable OCR for case \"%s\"."})
|
||||
static final class DisableOCR extends AbstractAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final AutoIngestJob job;
|
||||
|
||||
DisableOCR(AutoIngestJob job) {
|
||||
super(Bundle.AutoIngestAdminActions_disableOCR_title());
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
if (job == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(AutoIngestDashboardTopComponent.PREFERRED_ID);
|
||||
if (tc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoIngestDashboard dashboard = tc.getAutoIngestDashboard();
|
||||
if (dashboard != null) {
|
||||
dashboard.getPendingJobsPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
EventQueue.invokeLater(() -> {
|
||||
try {
|
||||
dashboard.getMonitor().changeOcrStateForCase(job.getManifest().getCaseName(), false);
|
||||
dashboard.getPendingJobsPanel().refresh(new AutoIngestNodeRefreshEvents.RefreshCaseEvent(dashboard.getMonitor(), job.getManifest().getCaseName()));
|
||||
} catch (AutoIngestMonitor.AutoIngestMonitorException ex) {
|
||||
String errorMessage = String.format(Bundle.AutoIngestAdminActions_disableOCR_error(), job.getManifest().getCaseName());
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
MessageNotifyUtil.Message.error(errorMessage);
|
||||
} finally {
|
||||
dashboard.getPendingJobsPanel().setCursor(Cursor.getDefaultCursor());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"AutoIngestAdminActions.progressDialogAction.title=Ingest Progress"})
|
||||
static final class ProgressDialogAction extends AbstractAction {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015-2018 Basis Technology Corp.
|
||||
* Copyright 2015-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -122,6 +122,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
private static final int RUNNING_TABLE_COL_PREFERRED_WIDTH = 175;
|
||||
private static final int PRIORITY_COLUMN_PREFERRED_WIDTH = 60;
|
||||
private static final int PRIORITY_COLUMN_MAX_WIDTH = 150;
|
||||
private static final int OCR_COLUMN_PREFERRED_WIDTH = 50;
|
||||
private static final int OCR_COLUMN_MAX_WIDTH = 150;
|
||||
private static final int ACTIVITY_TIME_COL_MIN_WIDTH = 250;
|
||||
private static final int ACTIVITY_TIME_COL_MAX_WIDTH = 450;
|
||||
private static final int TIME_COL_MIN_WIDTH = 30;
|
||||
@ -133,9 +135,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
private static final int ACTIVITY_COL_MIN_WIDTH = 70;
|
||||
private static final int ACTIVITY_COL_MAX_WIDTH = 2000;
|
||||
private static final int ACTIVITY_COL_PREFERRED_WIDTH = 300;
|
||||
private static final int STATUS_COL_MIN_WIDTH = 55;
|
||||
private static final int STATUS_COL_MIN_WIDTH = 50;
|
||||
private static final int STATUS_COL_MAX_WIDTH = 250;
|
||||
private static final int STATUS_COL_PREFERRED_WIDTH = 55;
|
||||
private static final int STATUS_COL_PREFERRED_WIDTH = 50;
|
||||
private static final int COMPLETED_TIME_COL_MIN_WIDTH = 30;
|
||||
private static final int COMPLETED_TIME_COL_MAX_WIDTH = 2000;
|
||||
private static final int COMPLETED_TIME_COL_PREFERRED_WIDTH = 280;
|
||||
@ -179,7 +181,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.Status=Status",
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.CaseFolder=Case Folder",
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.LocalJob= Local Job?",
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath= Manifest File Path"
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath= Manifest File Path",
|
||||
"AutoIngestControlPanel.JobsTableModel.ColumnHeader.OCR=OCR"
|
||||
})
|
||||
private enum JobsTableModelColumns {
|
||||
|
||||
@ -195,7 +198,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
CASE_DIRECTORY_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.CaseFolder")),
|
||||
IS_LOCAL_JOB(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.LocalJob")),
|
||||
MANIFEST_FILE_PATH(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath")),
|
||||
PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority"));
|
||||
PRIORITY(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority")),
|
||||
OCR(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.JobsTableModel.ColumnHeader.OCR"));
|
||||
private final String header;
|
||||
|
||||
private JobsTableModelColumns(String header) {
|
||||
@ -219,7 +223,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
CASE_DIRECTORY_PATH.getColumnHeader(),
|
||||
IS_LOCAL_JOB.getColumnHeader(),
|
||||
MANIFEST_FILE_PATH.getColumnHeader(),
|
||||
PRIORITY.getColumnHeader()};
|
||||
PRIORITY.getColumnHeader(),
|
||||
OCR.getColumnHeader()};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -406,6 +411,12 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
column.setMaxWidth(PRIORITY_COLUMN_MAX_WIDTH);
|
||||
column.setPreferredWidth(PRIORITY_COLUMN_PREFERRED_WIDTH);
|
||||
column.setWidth(PRIORITY_COLUMN_PREFERRED_WIDTH);
|
||||
|
||||
column = pendingTable.getColumn(JobsTableModelColumns.OCR.getColumnHeader());
|
||||
column.setCellRenderer(new OcrIconCellRenderer());
|
||||
column.setMaxWidth(OCR_COLUMN_MAX_WIDTH);
|
||||
column.setPreferredWidth(OCR_COLUMN_PREFERRED_WIDTH);
|
||||
column.setWidth(OCR_COLUMN_PREFERRED_WIDTH);
|
||||
|
||||
/**
|
||||
* Allow sorting when a column header is clicked.
|
||||
@ -457,6 +468,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.IS_LOCAL_JOB.getColumnHeader()));
|
||||
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader()));
|
||||
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()));
|
||||
runningTable.removeColumn(runningTable.getColumn(JobsTableModelColumns.OCR.getColumnHeader()));
|
||||
|
||||
/*
|
||||
* Set up a column to display the cases associated with the jobs.
|
||||
*/
|
||||
@ -553,6 +566,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.CASE_DIRECTORY_PATH.getColumnHeader()));
|
||||
completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.MANIFEST_FILE_PATH.getColumnHeader()));
|
||||
completedTable.removeColumn(completedTable.getColumn(JobsTableModelColumns.PRIORITY.getColumnHeader()));
|
||||
|
||||
/*
|
||||
* Set up a column to display the cases associated with the jobs.
|
||||
*/
|
||||
@ -603,6 +617,15 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
column.setMaxWidth(STATUS_COL_MAX_WIDTH);
|
||||
column.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH);
|
||||
column.setWidth(STATUS_COL_PREFERRED_WIDTH);
|
||||
|
||||
/*
|
||||
* Set up a column to display OCR enabled/disabled flag.
|
||||
*/
|
||||
column = completedTable.getColumn(JobsTableModelColumns.OCR.getColumnHeader());
|
||||
column.setCellRenderer(new OcrIconCellRenderer());
|
||||
column.setMaxWidth(OCR_COLUMN_MAX_WIDTH);
|
||||
column.setPreferredWidth(OCR_COLUMN_PREFERRED_WIDTH);
|
||||
column.setWidth(OCR_COLUMN_PREFERRED_WIDTH);
|
||||
|
||||
/*
|
||||
* Allow sorting when a column header is clicked.
|
||||
@ -856,6 +879,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
case JOB_COMPLETED:
|
||||
case CASE_DELETED:
|
||||
case REPROCESS_JOB:
|
||||
case OCR_STATE_CHANGE:
|
||||
updateExecutor.submit(new UpdateAllJobsTablesTask());
|
||||
break;
|
||||
case PAUSED_BY_USER_REQUEST:
|
||||
@ -1193,7 +1217,8 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
||||
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
|
||||
job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB
|
||||
job.getManifest().getFilePath(), // MANIFEST_FILE_PATH
|
||||
job.getPriority()}); // PRIORITY
|
||||
job.getPriority(), // PRIORITY
|
||||
job.getOcrEnabled()}); // OCR FLAG
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
sysLogger.log(Level.SEVERE, "Dashboard error refreshing table", ex);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotProvider;
|
||||
final class AutoIngestJob implements Comparable<AutoIngestJob>, IngestProgressSnapshotProvider, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int CURRENT_VERSION = 3;
|
||||
private static final int CURRENT_VERSION = 4;
|
||||
private static final int DEFAULT_PRIORITY = 0;
|
||||
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
|
||||
|
||||
@ -100,6 +100,11 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, IngestProgressSn
|
||||
private List<IngestThreadActivitySnapshot> ingestThreadsSnapshot;
|
||||
private List<Snapshot> ingestJobsSnapshot;
|
||||
private Map<String, Long> moduleRunTimesSnapshot;
|
||||
|
||||
/*
|
||||
* Version 4 fields.
|
||||
*/
|
||||
private boolean ocrEnabled;
|
||||
|
||||
/**
|
||||
* Constructs a new automated ingest job. All job state not specified in the
|
||||
@ -194,6 +199,11 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, IngestProgressSn
|
||||
this.ingestJobsSnapshot = Collections.emptyList();
|
||||
this.moduleRunTimesSnapshot = Collections.emptyMap();
|
||||
|
||||
/*
|
||||
* Version 4 fields
|
||||
*/
|
||||
this.ocrEnabled = nodeData.getOcrEnabled();
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
|
||||
}
|
||||
@ -253,6 +263,24 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, IngestProgressSn
|
||||
synchronized Integer getPriority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OCR flag for the job.
|
||||
*
|
||||
* @return Flag whether OCR is enabled/disabled.
|
||||
*/
|
||||
synchronized boolean getOcrEnabled() {
|
||||
return this.ocrEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OCR enabled/disabled flag for the job.
|
||||
*
|
||||
* @param enabled Flag whether OCR is enabled/disabled.
|
||||
*/
|
||||
synchronized void setOcrEnabled(boolean enabled) {
|
||||
this.ocrEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the processing stage of the job. The start date/time for the stage
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -31,7 +31,7 @@ import javax.lang.model.type.TypeKind;
|
||||
*/
|
||||
final class AutoIngestJobNodeData {
|
||||
|
||||
private static final int CURRENT_VERSION = 2;
|
||||
private static final int CURRENT_VERSION = 3;
|
||||
private static final int DEFAULT_PRIORITY = 0;
|
||||
|
||||
/*
|
||||
@ -47,7 +47,7 @@ final class AutoIngestJobNodeData {
|
||||
* data. This avoids the need to continuously enlarge the buffer. Once the
|
||||
* buffer has all the necessary data, it will be resized as appropriate.
|
||||
*/
|
||||
private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131637;
|
||||
private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131641;
|
||||
|
||||
/*
|
||||
* Version 0 fields.
|
||||
@ -78,6 +78,11 @@ final class AutoIngestJobNodeData {
|
||||
* Version 2 fields.
|
||||
*/
|
||||
private long dataSourceSize;
|
||||
|
||||
/*
|
||||
* Version 3 fields.
|
||||
*/
|
||||
private boolean ocrEnabled;
|
||||
|
||||
/**
|
||||
* Gets the current version of the auto ingest job coordination service node
|
||||
@ -115,6 +120,7 @@ final class AutoIngestJobNodeData {
|
||||
setProcessingStageStartDate(job.getProcessingStageStartDate());
|
||||
setProcessingStageDetails(job.getProcessingStageDetails());
|
||||
setDataSourceSize(job.getDataSourceSize());
|
||||
setOcrEnabled(job.getOcrEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,7 +134,7 @@ final class AutoIngestJobNodeData {
|
||||
if (null == nodeData || nodeData.length == 0) {
|
||||
throw new InvalidDataException(null == nodeData ? "Null nodeData byte array" : "Zero-length nodeData byte array");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set default values for all fields.
|
||||
*/
|
||||
@ -150,6 +156,7 @@ final class AutoIngestJobNodeData {
|
||||
this.processingStageDetailsDescription = "";
|
||||
this.processingStageDetailsStartDate = 0L;
|
||||
this.dataSourceSize = 0L;
|
||||
this.ocrEnabled = false;
|
||||
|
||||
/*
|
||||
* Get fields from node data.
|
||||
@ -192,6 +199,14 @@ final class AutoIngestJobNodeData {
|
||||
*/
|
||||
this.dataSourceSize = buffer.getLong();
|
||||
}
|
||||
|
||||
if (buffer.hasRemaining()) {
|
||||
/*
|
||||
* Get version 3 fields.
|
||||
*/
|
||||
int ocrFlag = buffer.getInt();
|
||||
this.ocrEnabled = (1 == ocrFlag);
|
||||
}
|
||||
|
||||
} catch (BufferUnderflowException ex) {
|
||||
throw new InvalidDataException("Node data is incomplete", ex);
|
||||
@ -234,6 +249,24 @@ final class AutoIngestJobNodeData {
|
||||
void setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OCR flag for the job.
|
||||
*
|
||||
* @return Flag whether OCR is enabled/disabled.
|
||||
*/
|
||||
boolean getOcrEnabled() {
|
||||
return this.ocrEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OCR enabled/disabled flag for the job.
|
||||
*
|
||||
* @param enabled Flag whether OCR is enabled/disabled.
|
||||
*/
|
||||
void setOcrEnabled(boolean enabled) {
|
||||
this.ocrEnabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times the job has crashed during processing.
|
||||
@ -567,6 +600,10 @@ final class AutoIngestJobNodeData {
|
||||
if (this.version >= 2) {
|
||||
buffer.putLong(this.dataSourceSize);
|
||||
}
|
||||
|
||||
if (this.version >= 3) {
|
||||
buffer.putInt(this.ocrEnabled ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the array
|
||||
|
@ -57,7 +57,8 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
"AutoIngestJobsNode.jobCreated.text=Job Created",
|
||||
"AutoIngestJobsNode.jobCompleted.text=Job Completed",
|
||||
"AutoIngestJobsNode.priority.text=Prioritized",
|
||||
"AutoIngestJobsNode.status.text=Status"
|
||||
"AutoIngestJobsNode.status.text=Status",
|
||||
"AutoIngestJobsNode.ocr.text=OCR"
|
||||
})
|
||||
|
||||
/**
|
||||
@ -98,12 +99,14 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
private final Stage jobStage;
|
||||
private final List<Snapshot> jobSnapshot;
|
||||
private final Integer jobPriority;
|
||||
private final Boolean ocrFlag;
|
||||
|
||||
AutoIngestJobWrapper(AutoIngestJob job) {
|
||||
autoIngestJob = job;
|
||||
jobStage = job.getProcessingStage();
|
||||
jobSnapshot = job.getIngestJobSnapshots();
|
||||
jobPriority = job.getPriority();
|
||||
ocrFlag = job.getOcrEnabled();
|
||||
}
|
||||
|
||||
AutoIngestJob getJob() {
|
||||
@ -123,11 +126,12 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
AutoIngestJob thisJob = this.autoIngestJob;
|
||||
AutoIngestJob otherJob = ((AutoIngestJobWrapper) other).autoIngestJob;
|
||||
|
||||
// Only equal if the manifest paths and processing stage details are the same.
|
||||
// Only equal if the manifest paths, processing stage details, priority, and OCR flag are the same.
|
||||
return thisJob.getManifest().getFilePath().equals(otherJob.getManifest().getFilePath())
|
||||
&& jobStage.equals(((AutoIngestJobWrapper) other).jobStage)
|
||||
&& jobSnapshot.equals(((AutoIngestJobWrapper) other).jobSnapshot)
|
||||
&& jobPriority.equals(((AutoIngestJobWrapper) other).jobPriority);
|
||||
&& jobPriority.equals(((AutoIngestJobWrapper) other).jobPriority)
|
||||
&& ocrFlag.equals(((AutoIngestJobWrapper) other).ocrFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -137,6 +141,7 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
hash = 23 * hash + Objects.hashCode(this.jobStage);
|
||||
hash = 23 * hash + Objects.hashCode(this.jobSnapshot);
|
||||
hash = 23 * hash + Objects.hashCode(this.jobPriority);
|
||||
hash = 23 * hash + Objects.hashCode(this.ocrFlag);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@ -171,6 +176,10 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
Integer getPriority() {
|
||||
return autoIngestJob.getPriority();
|
||||
}
|
||||
|
||||
boolean getOcrEnabled() {
|
||||
return autoIngestJob.getOcrEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -327,6 +336,8 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
jobWrapper.getManifest().getDateFileCreated()));
|
||||
ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(),
|
||||
jobWrapper.getPriority()));
|
||||
ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text(),
|
||||
jobWrapper.getOcrEnabled()));
|
||||
break;
|
||||
case RUNNING_JOB:
|
||||
AutoIngestJob.StageDetails status = jobWrapper.getProcessingStageDetails();
|
||||
@ -344,6 +355,8 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
jobWrapper.getCompletedDate()));
|
||||
ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(),
|
||||
jobWrapper.getErrorsOccurred() ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK));
|
||||
ss.put(new NodeProperty<>(Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text(),
|
||||
jobWrapper.getOcrEnabled()));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
@ -364,6 +377,11 @@ final class AutoIngestJobsNode extends AbstractNode {
|
||||
PrioritizationAction.DeprioritizeCaseAction deprioritizeCaseAction = new PrioritizationAction.DeprioritizeCaseAction(jobWrapper.getJob());
|
||||
deprioritizeCaseAction.setEnabled(jobWrapper.getPriority() > 0);
|
||||
actions.add(deprioritizeCaseAction);
|
||||
|
||||
actions.add(new AutoIngestAdminActions.EnableOCR(jobWrapper.getJob()));
|
||||
AutoIngestAdminActions.DisableOCR disableOCRAction = new AutoIngestAdminActions.DisableOCR(jobWrapper.getJob());
|
||||
disableOCRAction.setEnabled(jobWrapper.getOcrEnabled() == true);
|
||||
actions.add(disableOCRAction);
|
||||
break;
|
||||
case RUNNING_JOB:
|
||||
actions.add(new AutoIngestAdminActions.ProgressDialogAction(jobWrapper.getJob()));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Copyright 2018-2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -43,6 +43,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
|
||||
private static final int INITIAL_CASENAME_WIDTH = 170;
|
||||
private static final int INITIAL_DATASOURCE_WIDTH = 270;
|
||||
private static final int INITIAL_PRIORITIZED_WIDTH = 20;
|
||||
private static final int INITIAL_OCR_WIDTH = 20;
|
||||
private static final int INITIAL_STATUS_WIDTH = 20;
|
||||
private static final int INVALID_INDEX = -1;
|
||||
private final org.openide.explorer.view.OutlineView outlineView;
|
||||
@ -81,12 +82,18 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
|
||||
case PENDING_JOB:
|
||||
outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(),
|
||||
Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(),
|
||||
Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text());
|
||||
Bundle.AutoIngestJobsNode_priority_text(), Bundle.AutoIngestJobsNode_priority_text(),
|
||||
Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text());
|
||||
indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_priority_text());
|
||||
if (indexOfColumn != INVALID_INDEX) {
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_PRIORITIZED_WIDTH);
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new PrioritizedIconCellRenderer());
|
||||
}
|
||||
indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_ocr_text());
|
||||
if (indexOfColumn != INVALID_INDEX) {
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_OCR_WIDTH);
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new OcrIconCellRenderer());
|
||||
}
|
||||
break;
|
||||
case RUNNING_JOB:
|
||||
outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(),
|
||||
@ -102,7 +109,8 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
|
||||
outlineView.setPropertyColumns(Bundle.AutoIngestJobsNode_dataSource_text(), Bundle.AutoIngestJobsNode_dataSource_text(),
|
||||
Bundle.AutoIngestJobsNode_jobCreated_text(), Bundle.AutoIngestJobsNode_jobCreated_text(),
|
||||
Bundle.AutoIngestJobsNode_jobCompleted_text(), Bundle.AutoIngestJobsNode_jobCompleted_text(),
|
||||
Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text());
|
||||
Bundle.AutoIngestJobsNode_status_text(), Bundle.AutoIngestJobsNode_status_text(),
|
||||
Bundle.AutoIngestJobsNode_ocr_text(), Bundle.AutoIngestJobsNode_ocr_text());
|
||||
indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_jobCompleted_text());
|
||||
if (indexOfColumn != INVALID_INDEX) {
|
||||
outline.setColumnSorted(indexOfColumn, false, 1);
|
||||
@ -112,6 +120,11 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_STATUS_WIDTH);
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new StatusIconCellRenderer());
|
||||
}
|
||||
indexOfColumn = getColumnIndexByName(Bundle.AutoIngestJobsNode_ocr_text());
|
||||
if (indexOfColumn != INVALID_INDEX) {
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setPreferredWidth(INITIAL_OCR_WIDTH);
|
||||
outline.getColumnModel().getColumn(indexOfColumn).setCellRenderer(new OcrIconCellRenderer());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
@ -105,6 +105,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleError;
|
||||
import org.sleuthkit.autopsy.ingest.IngestStream;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleException;
|
||||
import org.sleuthkit.autopsy.keywordsearch.Server;
|
||||
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
@ -144,7 +145,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
ControlEventType.SHUTDOWN.toString(),
|
||||
ControlEventType.GENERATE_THREAD_DUMP_REQUEST.toString(),
|
||||
Event.CANCEL_JOB.toString(),
|
||||
Event.REPROCESS_JOB.toString()}));
|
||||
Event.REPROCESS_JOB.toString(),
|
||||
Event.OCR_STATE_CHANGE.toString()}));
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
|
||||
private static final long JOB_STATUS_EVENT_INTERVAL_SECONDS = 10;
|
||||
private static final String JOB_STATUS_PUBLISHING_THREAD_NAME = "AIM-job-status-event-publisher-%d";
|
||||
@ -308,6 +310,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
handleRemoteJobCancelEvent((AutoIngestJobCancelEvent) event);
|
||||
} else if (event instanceof AutoIngestJobReprocessEvent) {
|
||||
handleRemoteJobReprocessEvent((AutoIngestJobReprocessEvent) event);
|
||||
} else if (event instanceof AutoIngestOcrStateChangeEvent) {
|
||||
handleRemoteOcrEvent((AutoIngestOcrStateChangeEvent) event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -466,10 +470,42 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
|
||||
String hostName = event.getNodeName();
|
||||
hostNamesToLastMsgTime.put(hostName, Instant.now());
|
||||
// currently the only way to the get latest ZK manifest node contents is to do an input directory scan
|
||||
scanInputDirsNow();
|
||||
setChanged();
|
||||
notifyObservers(Event.CASE_PRIORITIZED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a case OCR enabled/disabled event from another node.
|
||||
*
|
||||
* @param event OCR enabled/disabled event from another auto ingest node.
|
||||
*/
|
||||
private void handleRemoteOcrEvent(AutoIngestOcrStateChangeEvent event) {
|
||||
switch (event.getEventType()) {
|
||||
case OCR_ENABLED:
|
||||
sysLogger.log(Level.INFO, "Received OCR enabled event for case {0} from user {1} on machine {2}",
|
||||
new Object[]{event.getCaseName(), event.getUserName(), event.getNodeName()});
|
||||
break;
|
||||
case OCR_DISABLED:
|
||||
sysLogger.log(Level.INFO, "Received OCR disabled event for case {0} from user {1} on machine {2}",
|
||||
new Object[]{event.getCaseName(), event.getUserName(), event.getNodeName()});
|
||||
break;
|
||||
default:
|
||||
sysLogger.log(Level.WARNING, "Received invalid OCR enabled/disabled event from user {0} on machine {1}",
|
||||
new Object[]{event.getUserName(), event.getNodeName()});
|
||||
break;
|
||||
}
|
||||
|
||||
String hostName = event.getNodeName();
|
||||
hostNamesToLastMsgTime.put(hostName, Instant.now());
|
||||
|
||||
// currently the only way to the get latest ZK manifest node contents is to do an input directory scan
|
||||
scanInputDirsNow();
|
||||
|
||||
setChanged();
|
||||
notifyObservers(Event.OCR_STATE_CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a case deletion event from another node by triggering an
|
||||
@ -2057,10 +2093,11 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
currentJob = job;
|
||||
// create a new job object based on latest ZK node data (i.e. instead of re-using potentially stale local pending AutoIngestJob object).
|
||||
currentJob = new AutoIngestJob(nodeData);
|
||||
break;
|
||||
|
||||
} catch (AutoIngestJobNodeData.InvalidDataException ex) {
|
||||
} catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJobException ex) {
|
||||
sysLogger.log(Level.WARNING, String.format("Unable to use node data for %s", manifestPath), ex);
|
||||
}
|
||||
}
|
||||
@ -2215,21 +2252,20 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
* auto ingest job.
|
||||
*/
|
||||
private void attemptJob() throws CoordinationServiceException, SharedConfigurationException, ServicesMonitorException, DatabaseServerDownException, KeywordSearchServerDownException, CaseManagementException, AnalysisStartupException, FileExportException, AutoIngestJobLoggerException, InterruptedException, AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException, IOException, JobMetricsCollectionException {
|
||||
updateConfiguration();
|
||||
if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
verifyRequiredSevicesAreRunning();
|
||||
if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
Case caseForJob = openCase();
|
||||
try {
|
||||
if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
updateConfiguration();
|
||||
if (currentJob.isCanceled() || jobProcessingTaskFuture.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
runIngestForJob(caseForJob);
|
||||
|
||||
} finally {
|
||||
try {
|
||||
Case.closeCurrentCase();
|
||||
@ -2242,7 +2278,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
|
||||
/**
|
||||
* Updates the ingest system settings by downloading the latest version
|
||||
* of the settings if using shared configuration.
|
||||
* of the settings if using shared configuration. Also updates the OCR
|
||||
* setting.
|
||||
*
|
||||
* @throws SharedConfigurationException if there is an error downloading
|
||||
* shared configuration.
|
||||
@ -2258,6 +2295,15 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
currentJob.setProcessingStage(AutoIngestJob.Stage.UPDATING_SHARED_CONFIG, Date.from(Instant.now()));
|
||||
new SharedConfiguration().downloadConfiguration();
|
||||
}
|
||||
|
||||
// update the OCR enabled/disabled setting
|
||||
if (currentJob.getOcrEnabled()) {
|
||||
sysLogger.log(Level.INFO, "Enabling OCR for job {0}", currentJob.getManifest().getFilePath());
|
||||
} else {
|
||||
sysLogger.log(Level.INFO, "Disabling OCR for job {0}", currentJob.getManifest().getFilePath());
|
||||
}
|
||||
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
|
||||
kwsService.changeOcrState(currentJob.getOcrEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3151,7 +3197,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
REPORT_STATE,
|
||||
CANCEL_JOB,
|
||||
REPROCESS_JOB,
|
||||
GENERATE_THREAD_DUMP_RESPONSE
|
||||
GENERATE_THREAD_DUMP_RESPONSE,
|
||||
OCR_STATE_CHANGE
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,7 +84,8 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
AutoIngestManager.Event.SHUTTING_DOWN.toString(),
|
||||
AutoIngestManager.Event.SHUTDOWN.toString(),
|
||||
AutoIngestManager.Event.RESUMED.toString(),
|
||||
AutoIngestManager.Event.GENERATE_THREAD_DUMP_RESPONSE.toString()}));
|
||||
AutoIngestManager.Event.GENERATE_THREAD_DUMP_RESPONSE.toString(),
|
||||
AutoIngestManager.Event.OCR_STATE_CHANGE.toString()}));
|
||||
private final AutopsyEventPublisher eventPublisher;
|
||||
private CoordinationService coordinationService;
|
||||
private final ScheduledThreadPoolExecutor coordSvcQueryExecutor;
|
||||
@ -166,6 +167,8 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
handleAutoIngestNodeStateEvent((AutoIngestNodeStateEvent) event);
|
||||
} else if (event instanceof ThreadDumpResponseEvent) {
|
||||
handleRemoteThreadDumpResponseEvent((ThreadDumpResponseEvent) event);
|
||||
} else if (event instanceof AutoIngestOcrStateChangeEvent) {
|
||||
handleOcrStateChangeEvent((AutoIngestOcrStateChangeEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,6 +231,15 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an OCR state change event.
|
||||
*
|
||||
* @param event OCR state change event.
|
||||
*/
|
||||
private void handleOcrStateChangeEvent(AutoIngestOcrStateChangeEvent event) {
|
||||
coordSvcQueryExecutor.submit(new StateRefreshTask());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an auto ingest job/case prioritization event.
|
||||
*
|
||||
@ -427,6 +439,51 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
||||
return new JobsSnapshot();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables OCR for all pending ingest jobs for a specified case.
|
||||
*
|
||||
* @param caseName The name of the case to enable OCR.
|
||||
*
|
||||
* @throws AutoIngestMonitorException If there is an error enabling OCR for the jobs for the case.
|
||||
*
|
||||
*/
|
||||
void changeOcrStateForCase(final String caseName, final boolean ocrState) throws AutoIngestMonitorException {
|
||||
List<AutoIngestJob> jobsToPrioritize = new ArrayList<>();
|
||||
synchronized (jobsLock) {
|
||||
for (AutoIngestJob pendingJob : getPendingJobs()) {
|
||||
if (pendingJob.getManifest().getCaseName().equals(caseName)) {
|
||||
jobsToPrioritize.add(pendingJob);
|
||||
}
|
||||
}
|
||||
if (!jobsToPrioritize.isEmpty()) {
|
||||
for (AutoIngestJob job : jobsToPrioritize) {
|
||||
String manifestNodePath = job.getManifest().getFilePath().toString();
|
||||
try {
|
||||
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath));
|
||||
nodeData.setOcrEnabled(ocrState);
|
||||
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray());
|
||||
} catch (AutoIngestJobNodeData.InvalidDataException | CoordinationServiceException | InterruptedException ex) {
|
||||
throw new AutoIngestMonitorException("Error enabling OCR for job " + job.toString(), ex);
|
||||
}
|
||||
job.setOcrEnabled(ocrState);
|
||||
|
||||
/**
|
||||
* Update job object in pending jobs queue
|
||||
*/
|
||||
jobsSnapshot.addOrReplacePendingJob(job);
|
||||
}
|
||||
|
||||
/*
|
||||
* Publish the OCR enabled event.
|
||||
*/
|
||||
new Thread(() -> {
|
||||
eventPublisher.publishRemotely(new AutoIngestOcrStateChangeEvent(LOCAL_HOST_NAME, caseName,
|
||||
AutoIngestManager.getSystemUserNameProperty(), ocrState));
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the priority (set to zero) of all pending ingest jobs for a
|
||||
|
@ -69,7 +69,7 @@ class AutoIngestNodeRefreshEvents {
|
||||
private final String caseName;
|
||||
|
||||
/**
|
||||
* Contructs a RefreshCaseEvent
|
||||
* Constructs a RefreshCaseEvent
|
||||
*
|
||||
* @param monitor The monitor that will provide access to the current state of the jobs lists.
|
||||
* @param name The name of the case whose nodes should be refreshed.
|
||||
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
|
||||
/**
|
||||
* Event published when an automated ingest manager enables or disables OCR on a case.
|
||||
*/
|
||||
public final class AutoIngestOcrStateChangeEvent extends AutopsyEvent implements Serializable {
|
||||
|
||||
/**
|
||||
* Possible event types
|
||||
*/
|
||||
enum EventType {
|
||||
OCR_ENABLED,
|
||||
OCR_DISABLED
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String caseName;
|
||||
private final String nodeName;
|
||||
private final String userName;
|
||||
private final EventType eventType;
|
||||
|
||||
/**
|
||||
* Constructs an event published when an automated ingest manager
|
||||
* enables or disables OCR on a case.
|
||||
*
|
||||
* @param caseName The name of the case.
|
||||
* @param nodeName The host name of the node that enabled/disabled OCR.
|
||||
* @param userName The logged in user
|
||||
* @param ocrState Flag whether OCR is enabled/disabled
|
||||
*/
|
||||
public AutoIngestOcrStateChangeEvent(String nodeName, String caseName, String userName, boolean ocrState) {
|
||||
super(AutoIngestManager.Event.OCR_STATE_CHANGE.toString(), null, null);
|
||||
this.caseName = caseName;
|
||||
this.nodeName = nodeName;
|
||||
this.userName = userName;
|
||||
if (ocrState == true) {
|
||||
this.eventType = EventType.OCR_ENABLED;
|
||||
} else {
|
||||
this.eventType = EventType.OCR_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the prioritized case.
|
||||
*
|
||||
* @return The case name.
|
||||
*/
|
||||
public String getCaseName() {
|
||||
return caseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host name of the node that prioritized the case.
|
||||
*
|
||||
* @return The host name of the node.
|
||||
*/
|
||||
public String getNodeName() {
|
||||
return nodeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user logged in to the node that prioritized the case.
|
||||
*
|
||||
* @return The user name
|
||||
*/
|
||||
String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of prioritization
|
||||
*
|
||||
* @return The type
|
||||
*/
|
||||
EventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
}
|
@ -10,6 +10,10 @@ AinStatusNode.status.title=Status
|
||||
AinStatusNode.status.unknown=Unknown
|
||||
AutoIngestAdminActions.cancelJobAction.title=Cancel Job
|
||||
AutoIngestAdminActions.cancelModuleAction.title=Cancel Module
|
||||
AutoIngestAdminActions.disableOCR.error=Failed to disable OCR for case "%s".
|
||||
AutoIngestAdminActions.disableOCR.title=Disable OCR For This Case
|
||||
AutoIngestAdminActions.enableOCR.error=Failed to enable OCR for case "%s".
|
||||
AutoIngestAdminActions.enableOCR.title=Enable OCR For This Case
|
||||
AutoIngestAdminActions.getThreadDump.title=Generate Thread Dump
|
||||
AutoIngestAdminActions.pause.title=Pause Node
|
||||
AutoIngestAdminActions.progressDialogAction.title=Ingest Progress
|
||||
@ -71,6 +75,7 @@ AutoIngestControlPanel.JobsTableModel.ColumnHeader.HostName=Host Name
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.ImageFolder=Data Source
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.LocalJob=\ Local Job?
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.ManifestFilePath=\ Manifest File Path
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.OCR=OCR
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.Priority=Prioritized
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.Stage=Stage
|
||||
AutoIngestControlPanel.JobsTableModel.ColumnHeader.StageTime=Time in Stage
|
||||
@ -130,6 +135,7 @@ AutoIngestJobsNode.dataSource.text=Data Source
|
||||
AutoIngestJobsNode.hostName.text=Host Name
|
||||
AutoIngestJobsNode.jobCompleted.text=Job Completed
|
||||
AutoIngestJobsNode.jobCreated.text=Job Created
|
||||
AutoIngestJobsNode.ocr.text=OCR
|
||||
AutoIngestJobsNode.prioritized.false=No
|
||||
AutoIngestJobsNode.prioritized.true=Yes
|
||||
AutoIngestJobsNode.priority.text=Prioritized
|
||||
@ -206,9 +212,7 @@ DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}...
|
||||
DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}...
|
||||
DeleteCaseTask.progress.startMessage=Starting deletion...
|
||||
DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes
|
||||
# {0} - item count
|
||||
DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}
|
||||
# {0} - item count
|
||||
DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}
|
||||
DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service
|
||||
# {0} - node path
|
||||
@ -224,6 +228,8 @@ DeleteOrphanManifestNodesTask.progress.gettingManifestNodes=Querying the coordin
|
||||
DeleteOrphanManifestNodesTask.progress.lookingForOrphanedManifestFileZnodes=Looking for orphaned manifest file znodes
|
||||
DeleteOrphanManifestNodesTask.progress.startMessage=Starting orphaned manifest file znode cleanup
|
||||
HINT_CasesDashboardTopComponent=This is an adminstrative dashboard for multi-user cases
|
||||
OcrIconCellRenderer.disabled.tooltiptext=This job does not have OCR enabled.
|
||||
OcrIconCellRenderer.enabled.tooltiptext=This job has OCR enabled.
|
||||
OpenAutoIngestLogAction.deletedLogErrorMsg=The case auto ingest log has been deleted.
|
||||
OpenAutoIngestLogAction.logOpenFailedErrorMsg=Failed to open case auto ingest log. See application log for details.
|
||||
OpenAutoIngestLogAction.menuItemText=Open Auto Ingest Log File
|
||||
@ -333,7 +339,7 @@ PrioritizationAction.deprioritizeCaseAction.error=Failed to deprioritize case "%
|
||||
PrioritizationAction.deprioritizeCaseAction.title=Deprioritize Case
|
||||
PrioritizationAction.deprioritizeJobAction.error=Failed to deprioritize job "%s".
|
||||
PrioritizationAction.deprioritizeJobAction.title=Deprioritize Job
|
||||
PrioritizationAction.prioritizeCaseAction.error==Failed to prioritize case "%s".
|
||||
PrioritizationAction.prioritizeCaseAction.error=Failed to prioritize case "%s".
|
||||
PrioritizationAction.prioritizeCaseAction.title=Prioritize Case
|
||||
PrioritizationAction.prioritizeJobAction.error=Failed to prioritize job "%s".
|
||||
PrioritizationAction.prioritizeJobAction.title=Prioritize Job
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JTable;
|
||||
import static javax.swing.SwingConstants.CENTER;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.ImageUtilities;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
|
||||
/**
|
||||
* A JTable and Outline view cell renderer that represents whether OCR is enabled for the job.
|
||||
*/
|
||||
class OcrIconCellRenderer extends GrayableCellRenderer {
|
||||
|
||||
@Messages({
|
||||
"OcrIconCellRenderer.enabled.tooltiptext=This job has OCR enabled.",
|
||||
"OcrIconCellRenderer.disabled.tooltiptext=This job does not have OCR enabled."
|
||||
})
|
||||
private static final long serialVersionUID = 1L;
|
||||
static final ImageIcon checkedIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/tick.png", false));
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
setHorizontalAlignment(CENTER);
|
||||
Object switchValue = null;
|
||||
if ((value instanceof NodeProperty)) {
|
||||
//The Outline view has properties in the cell, the value contained in the property is what we want
|
||||
try {
|
||||
switchValue = ((Node.Property) value).getValue();
|
||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||
//Unable to get the value from the NodeProperty no Icon will be displayed
|
||||
}
|
||||
} else {
|
||||
//JTables contain the value we want directly in the cell
|
||||
switchValue = value;
|
||||
}
|
||||
if (switchValue instanceof Boolean && (boolean) switchValue == true) {
|
||||
setIcon(checkedIcon);
|
||||
setToolTipText(org.openide.util.NbBundle.getMessage(OcrIconCellRenderer.class, "OcrIconCellRenderer.enabled.tooltiptext"));
|
||||
} else {
|
||||
setIcon(null);
|
||||
if (switchValue instanceof Boolean) {
|
||||
setToolTipText(org.openide.util.NbBundle.getMessage(OcrIconCellRenderer.class, "OcrIconCellRenderer.disabled.tooltiptext"));
|
||||
}
|
||||
}
|
||||
grayCellIfTableNotEnabled(table, isSelected);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
@ -193,7 +193,7 @@ abstract class PrioritizationAction extends AbstractAction {
|
||||
* AutoIngestJob is a part of.
|
||||
*/
|
||||
@Messages({"PrioritizationAction.prioritizeCaseAction.title=Prioritize Case",
|
||||
"PrioritizationAction.prioritizeCaseAction.error==Failed to prioritize case \"%s\"."})
|
||||
"PrioritizationAction.prioritizeCaseAction.error=Failed to prioritize case \"%s\"."})
|
||||
static final class PrioritizeCaseAction extends PrioritizationAction {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -462,4 +462,17 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag to enable or disable OCR on all future text indexing. Also sets the
|
||||
* the "Limited OCR" functionality accordingly.
|
||||
*
|
||||
* @param state Boolean flag to enable/disable OCR. Set to True to enable
|
||||
* OCR, or False to disable it.
|
||||
*/
|
||||
@Override
|
||||
public void changeOcrState(boolean state) {
|
||||
KeywordSearchSettings.setOcrOption(state);
|
||||
KeywordSearchSettings.setLimitedOcrOption(state);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user