Merge branch 'sleuthkit:develop' into develop

This commit is contained in:
Seb2lyon 2021-06-15 21:27:36 +02:00
commit c4420b6c91
17 changed files with 629 additions and 56 deletions

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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 {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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()));

View File

@ -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:
}

View File

@ -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
}
/**

View File

@ -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

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}
}