Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
BaseDataSourceSummaryPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.datasourcesummary.ui;
20 
21 import java.beans.PropertyChangeEvent;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.function.Predicate;
27 import java.util.logging.Level;
28 import java.util.stream.Collectors;
29 import javax.swing.JPanel;
30 import javax.swing.SwingWorker;
31 import org.openide.util.NbBundle.Messages;
47 import org.sleuthkit.datamodel.AbstractFile;
48 import org.sleuthkit.datamodel.BlackboardArtifact;
49 import org.sleuthkit.datamodel.Content;
50 import org.sleuthkit.datamodel.DataSource;
51 import org.sleuthkit.datamodel.TskCoreException;
52 
56 abstract class BaseDataSourceSummaryPanel extends JPanel {
57 
58  private static final long serialVersionUID = 1L;
59 
60  private static final Logger logger = Logger.getLogger(BaseDataSourceSummaryPanel.class.getName());
61 
62  private final SwingWorkerSequentialExecutor executor = new SwingWorkerSequentialExecutor();
63  private final IngestModuleCheckUtil ingestModuleCheck = new IngestModuleCheckUtil();
64  private final EventUpdateHandler updateHandler;
65  private final List<UpdateGovernor> governors;
66 
67  private DataSource dataSource;
68 
75  private final UpdateGovernor updateGovernor = new UpdateGovernor() {
84  private boolean isInDataSource(BlackboardArtifact art, DataSource ds) {
85  try {
86 
87  return (art.getDataSource() != null && art.getDataSource().getId() == ds.getId());
88  } catch (TskCoreException ex) {
89  logger.log(Level.WARNING, "There was an error fetching datasource for artifact.", ex);
90  return false;
91  }
92  }
93 
94  @Override
95  public boolean isRefreshRequired(ModuleDataEvent evt) {
96  DataSource ds = getDataSource();
97  // make sure there is an event.
98  if (ds == null || evt == null) {
99  return false;
100  }
101 
102  //if there are no artifacts with matching datasource, return
103  // if no artifacts are present, pass it on just in case there was something wrong with ModuleDataEvent
104  if (evt.getArtifacts() != null
105  && !evt.getArtifacts().isEmpty()
106  && !evt.getArtifacts().stream().anyMatch((art) -> isInDataSource(art, ds))) {
107  return false;
108  }
109 
110  // otherwise, see if there is something that wants updates
111  for (UpdateGovernor governor : governors) {
112  if (governor.isRefreshRequired(evt)) {
113  return true;
114  }
115  }
116 
117  return false;
118  }
119 
120  @Override
121  public boolean isRefreshRequired(ModuleContentEvent evt) {
122  DataSource ds = getDataSource();
123  // make sure there is an event.
124  if (ds == null || evt == null) {
125  return false;
126  }
127 
128  try {
129  // if the underlying content has a datasource and that datasource != the
130  // current datasource, return false
131  if (evt.getSource() instanceof Content
132  && ((Content) evt.getSource()).getDataSource() != null
133  && ((Content) evt.getSource()).getDataSource().getId() != ds.getId()) {
134  return false;
135  }
136  } catch (TskCoreException ex) {
137  // on an exception, keep going for tolerance sake
138  logger.log(Level.WARNING, "There was an error fetching datasource for content.", ex);
139  }
140 
141  for (UpdateGovernor governor : governors) {
142  if (governor.isRefreshRequired(evt)) {
143  return true;
144  }
145  }
146 
147  return false;
148  }
149 
150  @Override
151  public boolean isRefreshRequired(AbstractFile file) {
152  DataSource currentDataSource = getDataSource();
153  if (currentDataSource == null || file == null) {
154  return false;
155  }
156 
157  // make sure the file is for the current data source
158  Long fileDsId = null;
159  try {
160  Content fileDataSource = file.getDataSource();
161  fileDsId = fileDataSource.getId();
162  } catch (TskCoreException ex) {
163  logger.log(Level.WARNING, "Unable to get the datasource for newly added file", ex);
164  }
165 
166  if (fileDsId != null && currentDataSource.getId() == fileDsId) {
167  for (UpdateGovernor governor : governors) {
168  if (governor.isRefreshRequired(file)) {
169  return true;
170  }
171  }
172  }
173 
174  return false;
175  }
176 
177  @Override
178  public boolean isRefreshRequired(IngestJobEvent evt) {
179  for (UpdateGovernor governor : governors) {
180  if (governor.isRefreshRequired(evt)) {
181  return true;
182  }
183  }
184 
185  return false;
186  }
187 
188  @Override
189  public boolean isRefreshRequiredForCaseEvent(PropertyChangeEvent evt) {
190  for (UpdateGovernor governor : governors) {
191  if (governor.isRefreshRequiredForCaseEvent(evt)) {
192  return true;
193  }
194  }
195 
196  return false;
197  }
198 
199  @Override
200  public Set<Case.Events> getCaseEventUpdates() {
201  // return the union of all case events sets from delegates.
202  return governors.stream()
203  .filter(governor -> governor.getCaseEventUpdates() != null)
204  .flatMap(governor -> governor.getCaseEventUpdates().stream())
205  .collect(Collectors.toSet());
206  }
207 
208  @Override
209  public Set<IngestJobEvent> getIngestJobEventUpdates() {
210  // return the union of all case events sets from delegates.
211  return governors.stream()
212  .filter(governor -> governor.getIngestJobEventUpdates() != null)
213  .flatMap(governor -> governor.getIngestJobEventUpdates().stream())
214  .collect(Collectors.toSet());
215  }
216  };
217 
224  protected BaseDataSourceSummaryPanel(UpdateGovernor... governors) {
225  this.governors = (governors == null) ? Collections.emptyList() : Arrays.asList(governors);
226  this.updateHandler = new EventUpdateHandler(this::onRefresh, updateGovernor);
227  this.updateHandler.register();
228  }
229 
233  public void close() {
234  executor.cancelRunning();
235  updateHandler.unregister();
236  }
237 
243  synchronized void setDataSource(DataSource dataSource) {
244  this.dataSource = dataSource;
245  this.executor.cancelRunning();
246  onNewDataSource(this.dataSource);
247  }
248 
252  protected synchronized DataSource getDataSource() {
253  return this.dataSource;
254  }
255 
262  protected void submit(List<? extends SwingWorker<?, ?>> workers) {
263  executor.submit(workers);
264  }
265 
271  synchronized void onRefresh() {
272  // trigger on new data source with the current data source
273  fetchInformation(this.dataSource);
274  }
275 
282  protected abstract void fetchInformation(DataSource dataSource);
283 
292  protected void fetchInformation(List<DataFetchComponents<DataSource, ?>> dataFetchComponents, DataSource dataSource) {
293  if (dataSource == null || !Case.isCaseOpen()) {
294  dataFetchComponents.forEach((item) -> item.getResultHandler()
295  .accept(DataFetchResult.getSuccessResult(null)));
296  } else {
297  // create swing workers to run for each loadable item
298  List<DataFetchWorker<?, ?>> workers = dataFetchComponents
299  .stream()
300  .map((components) -> new DataFetchWorker<>(components, dataSource))
301  .collect(Collectors.toList());
302 
303  // submit swing workers to run
304  if (!workers.isEmpty()) {
305  submit(workers);
306  }
307  }
308  }
309 
315  protected abstract void onNewDataSource(DataSource dataSource);
316 
326  protected void onNewDataSource(
327  List<DataFetchComponents<DataSource, ?>> dataFetchComponents,
328  List<? extends LoadableComponent<?>> loadableComponents,
329  DataSource dataSource) {
330  // if no data source is present or the case is not open,
331  // set results for tables to null.
332  if (dataSource == null || !Case.isCaseOpen()) {
333  dataFetchComponents.forEach((item) -> item.getResultHandler()
334  .accept(DataFetchResult.getSuccessResult(null)));
335 
336  } else {
337  // set tables to display loading screen
338  loadableComponents.forEach((table) -> table.showDefaultLoadingMessage());
339 
340  fetchInformation(dataSource);
341  }
342  }
343 
351  @Messages({
352  "# {0} - module name",
353  "BaseDataSourceSummaryPanel_defaultNotIngestMessage=The {0} ingest module has not been run on this data source."
354  })
355  protected String getDefaultNoIngestMessage(String moduleName) {
356  return Bundle.BaseDataSourceSummaryPanel_defaultNotIngestMessage(moduleName);
357  }
358 
364  protected IngestModuleCheckUtil getIngestModuleCheckUtil() {
365  return this.ingestModuleCheck;
366  }
367 
381  protected <T> void showResultWithModuleCheck(LoadableComponent<List<T>> component, DataFetchResult<List<T>> result, String factoryClass, String moduleName) {
382  Predicate<List<T>> hasResults = (lst) -> lst != null && !lst.isEmpty();
383  showResultWithModuleCheck(component, result, hasResults, factoryClass, moduleName);
384  }
385 
401  protected <T> void showResultWithModuleCheck(LoadableComponent<T> component, DataFetchResult<T> result,
402  Predicate<T> hasResults, String factoryClass, String moduleName) {
403 
404  if (result != null && result.getResultType() == ResultType.SUCCESS && !hasResults.test(result.getData())) {
405  try {
406  if (!ingestModuleCheck.isModuleIngested(getDataSource(), factoryClass)) {
407  component.showMessage(getDefaultNoIngestMessage(moduleName));
408  return;
409  }
410  } catch (TskCoreException | SleuthkitCaseProviderException ex) {
411  logger.log(Level.WARNING, "There was an error while checking for ingest modules for datasource.", ex);
412  }
413  }
414 
415  component.showDataFetchResult(result);
416  }
417 }

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.