19package org.sleuthkit.autopsy.datasourcesummary.ui;
21import java.beans.PropertyChangeEvent;
22import java.nio.file.Path;
23import java.nio.file.Paths;
24import java.util.Arrays;
25import java.util.Collections;
28import java.util.logging.Level;
29import java.util.regex.Matcher;
30import java.util.regex.Pattern;
31import java.util.stream.Collectors;
32import javax.swing.JPanel;
33import javax.swing.SwingWorker;
34import org.apache.commons.collections.CollectionUtils;
35import org.apache.commons.io.FilenameUtils;
36import org.apache.commons.lang3.StringUtils;
37import org.openide.util.NbBundle.Messages;
38import org.sleuthkit.autopsy.casemodule.Case;
39import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
40import org.sleuthkit.autopsy.coreutils.Logger;
41import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
42import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
43import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker.DataFetchComponents;
44import org.sleuthkit.autopsy.datasourcesummary.datamodel.DataFetcher;
45import org.sleuthkit.autopsy.datasourcesummary.uiutils.EventUpdateHandler;
46import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.DefaultMenuItem;
47import org.sleuthkit.autopsy.datasourcesummary.uiutils.GuiCellModel.MenuItem;
48import org.sleuthkit.autopsy.datasourcesummary.uiutils.LoadableComponent;
49import org.sleuthkit.autopsy.datasourcesummary.uiutils.SwingWorkerSequentialExecutor;
50import org.sleuthkit.autopsy.datasourcesummary.uiutils.UpdateGovernor;
51import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
52import org.sleuthkit.autopsy.directorytree.ViewContextAction;
53import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent;
54import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
55import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
56import org.sleuthkit.datamodel.AbstractFile;
57import org.sleuthkit.datamodel.BlackboardArtifact;
58import org.sleuthkit.datamodel.Content;
59import org.sleuthkit.datamodel.DataSource;
60import org.sleuthkit.datamodel.TskCoreException;
65@Messages({
"BaseDataSourceSummaryPanel_goToArtifact=View Source Result",
66 "BaseDataSourceSummaryPanel_goToFile=View Source File in Directory"})
67abstract class BaseDataSourceSummaryPanel extends JPanel {
69 private static final long serialVersionUID = 1L;
75 private final List<UpdateGovernor> governors;
77 private Runnable notifyParentClose =
null;
79 private DataSource dataSource;
96 private boolean isInDataSource(BlackboardArtifact art, DataSource ds) {
99 return (art.getDataSource() !=
null && art.getDataSource().getId() == ds.getId());
100 }
catch (TskCoreException ex) {
101 logger.log(Level.WARNING,
"There was an error fetching datasource for artifact.", ex);
108 DataSource ds = getDataSource();
110 if (ds ==
null || evt ==
null) {
116 if (evt.getArtifacts() !=
null
117 && !evt.getArtifacts().isEmpty()
118 && !evt.getArtifacts().stream().anyMatch((art) -> isInDataSource(art, ds))) {
124 if (governor.isRefreshRequired(evt)) {
134 DataSource ds = getDataSource();
136 if (ds ==
null || evt ==
null) {
143 if (evt.getSource() instanceof Content
144 && ((Content) evt.getSource()).getDataSource() !=
null
145 && ((Content) evt.getSource()).getDataSource().getId() != ds.getId()) {
148 }
catch (TskCoreException ex) {
150 logger.log(Level.WARNING,
"There was an error fetching datasource for content.", ex);
154 if (governor.isRefreshRequired(evt)) {
163 public boolean isRefreshRequired(AbstractFile file) {
164 DataSource currentDataSource = getDataSource();
165 if (currentDataSource ==
null || file ==
null) {
170 Long fileDsId =
null;
172 Content fileDataSource = file.getDataSource();
173 fileDsId = fileDataSource.getId();
174 }
catch (TskCoreException ex) {
175 logger.log(Level.WARNING,
"Unable to get the datasource for newly added file", ex);
178 if (fileDsId !=
null && currentDataSource.getId() == fileDsId) {
180 if (governor.isRefreshRequired(file)) {
192 if (governor.isRefreshRequired(evt)) {
201 public boolean isRefreshRequiredForCaseEvent(PropertyChangeEvent evt) {
203 if (governor.isRefreshRequiredForCaseEvent(evt)) {
212 public Set<
Case.
Events> getCaseEventUpdates() {
214 return governors.stream()
215 .filter(governor -> governor.getCaseEventUpdates() !=
null)
216 .flatMap(governor -> governor.getCaseEventUpdates().stream())
217 .collect(Collectors.toSet());
221 public Set<IngestJobEvent> getIngestJobEventUpdates() {
223 return governors.stream()
224 .filter(governor -> governor.getIngestJobEventUpdates() !=
null)
225 .flatMap(governor -> governor.getIngestJobEventUpdates().stream())
226 .collect(Collectors.toSet());
236 protected BaseDataSourceSummaryPanel(
UpdateGovernor... governors) {
237 this.governors = (governors ==
null) ? Collections.emptyList() : Arrays.asList(governors);
245 this.updateHandler.register();
255 protected MenuItem getArtifactNavigateItem(BlackboardArtifact artifact) {
256 if (artifact ==
null) {
261 Bundle.BaseDataSourceSummaryPanel_goToArtifact(),
263 final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
266 if (dtc != null && artifact != null) {
267 dtc.viewArtifact(artifact);
274 private static final Pattern windowsDrivePattern = Pattern.compile(
"^[A-Za-z]\\:(.*)$");
283 private String normalizePath(String path) {
288 String trimmed = path.trim();
289 Matcher match = windowsDrivePattern.matcher(trimmed);
291 return FilenameUtils.normalize(match.group(1),
true);
293 return FilenameUtils.normalize(trimmed,
true);
303 protected MenuItem getFileNavigateItem(String path) {
304 if (StringUtils.isNotBlank(path)) {
305 Path p = Paths.get(path);
306 String fileName = normalizePath(p.getFileName().toString());
307 String directory = normalizePath(p.getParent().toString());
309 if (fileName !=
null && directory !=
null) {
312 if (CollectionUtils.isNotEmpty(files)) {
313 return getFileNavigateItem(files.get(0));
316 logger.log(Level.WARNING,
"There was an error fetching file for path: " + path, ex);
331 protected MenuItem getFileNavigateItem(AbstractFile file) {
337 Bundle.BaseDataSourceSummaryPanel_goToFile(),
339 new ViewContextAction(Bundle.BaseDataSourceSummaryPanel_goToFile(), file)
340 .actionPerformed(null);
349 public void close() {
350 executor.cancelRunning();
351 updateHandler.unregister();
359 synchronized void setDataSource(DataSource dataSource) {
360 this.dataSource = dataSource;
361 this.executor.cancelRunning();
362 onNewDataSource(this.dataSource);
368 protected void notifyParentClose() {
369 if (notifyParentClose !=
null) {
370 notifyParentClose.run();
379 void setParentCloseListener(Runnable action) {
380 notifyParentClose = action;
386 protected synchronized DataSource getDataSource() {
387 return this.dataSource;
396 protected void submit(List<? extends SwingWorker<?, ?>> workers) {
397 executor.submit(workers);
405 synchronized void onRefresh() {
407 fetchInformation(this.dataSource);
416 protected abstract void fetchInformation(DataSource dataSource);
428 dataFetchComponents.forEach((item) -> item.getResultHandler()
432 List<DataFetchWorker<?, ?>> workers = dataFetchComponents
435 .collect(Collectors.toList());
438 if (!workers.isEmpty()) {
449 protected abstract void onNewDataSource(DataSource dataSource);
460 protected static <T> T getFetchResult(
462 String sheetName, DataSource ds) {
465 return dataFetcher.runQuery(ds);
466 }
catch (Exception ex) {
467 logger.log(Level.WARNING,
468 String.format(
"There was an error while acquiring data for exporting worksheet(s): '%s' for dataSource: %s",
469 sheetName ==
null ?
"<null>" : sheetName,
470 ds ==
null || ds.getName() ==
null ?
"<null>" : ds.getName()), ex);
484 protected void onNewDataSource(
487 DataSource dataSource) {
491 dataFetchComponents.forEach((item) -> item.getResultHandler()
496 loadableComponents.forEach((table) -> table.showDefaultLoadingMessage());
498 fetchInformation(dataSource);
SleuthkitCase getSleuthkitCase()
static Case getCurrentCaseThrows()
static boolean isCaseOpen()
synchronized static Logger getLogger(String name)
static< R > DataFetchResult< R > getSuccessResult(R data)