Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AddImageWizardAddingProgressPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2018 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.casemodule;
20 
21 import java.awt.Color;
22 import java.awt.Cursor;
23 import java.awt.EventQueue;
24 import java.awt.Window;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Set;
31 import java.util.UUID;
32 import java.util.logging.Level;
33 import javax.swing.JOptionPane;
34 import javax.swing.SwingUtilities;
35 import javax.swing.event.ChangeEvent;
36 import javax.swing.event.ChangeListener;
37 import org.openide.WizardDescriptor;
38 import org.openide.util.HelpCtx;
39 import org.openide.util.Lookup;
40 import org.openide.util.NbBundle;
41 import org.openide.windows.WindowManager;
49 import org.sleuthkit.datamodel.Content;
51 import org.sleuthkit.datamodel.Host;
52 
61 @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
62 class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
63 
64  private boolean readyToIngest = false;
65  // task that will clean up the created database file if the wizard is cancelled before it finishes
66  private AddImageAction.CleanupTask cleanupTask;
67 
68  private final AddImageAction addImageAction;
69 
70  private DataSourceProcessor dsProcessor = null;
71  private boolean cancelled;
76  private boolean imgAdded = false;
77  private boolean ingested = false;
82  private AddImageWizardAddingProgressVisual component;
83  private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
84  private final List<Content> newContents = Collections.synchronizedList(new ArrayList<>());
85  private final DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
86  private IngestJobSettings ingestJobSettings;
87 
88  AddImageWizardAddingProgressPanel(AddImageAction action) {
89  this.addImageAction = action;
90  }
91 
92  DSPProgressMonitorImpl getDSPProgressMonitorImpl() {
93  return dspProgressMonitorImpl;
94  }
95 
97 
98  @Override
99  public void setIndeterminate(final boolean indeterminate) {
100  // update the progress bar asynchronously
101  EventQueue.invokeLater(new Runnable() {
102  @Override
103  public void run() {
104  getComponent().getProgressBar().setIndeterminate(indeterminate);
105  }
106  });
107  }
108 
109  @Override
110  public void setProgress(final int progress) {
111  // update the progress bar asynchronously
112  EventQueue.invokeLater(new Runnable() {
113  @Override
114  public void run() {
115  getComponent().getProgressBar().setValue(progress);
116  }
117  });
118  }
119 
120  @Override
121  public void setProgressMax(final int max) {
122  // update the progress bar asynchronously
123  EventQueue.invokeLater(new Runnable() {
124  @Override
125  public void run() {
126  getComponent().getProgressBar().setMaximum(max);
127  }
128  });
129  }
130 
131  @Override
132  public void setProgressText(final String text) {
133  // update the progress UI asynchronously
134  EventQueue.invokeLater(new Runnable() {
135  @Override
136  public void run() {
137  getComponent().setProgressMsgText(text);
138  }
139  });
140  }
141 
142  }
143 
154  @Override
155  public AddImageWizardAddingProgressVisual getComponent() {
156  if (component == null) {
157  component = new AddImageWizardAddingProgressVisual();
158  }
159  return component;
160  }
161 
168  @Override
169  public HelpCtx getHelp() {
170  // Show no Help button for this panel:
171  return HelpCtx.DEFAULT_HELP;
172  }
173 
180  @Override
181  public boolean isValid() {
182  // set the focus to the next button of the wizard dialog if it's enabled
183  if (imgAdded) {
184  Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton(
185  NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.isValid.focusNext"));
186  }
187 
188  return imgAdded;
189  }
190 
194  void setStateStarted() {
195  component.getProgressBar().setIndeterminate(true);
196  component.setProgressBarTextAndColor(
197  NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.stateStarted.progressBarText"), 0, Color.black);
198  }
199 
203  void setStateFinished() {
204  imgAdded = true;
205  getComponent().setStateFinished();
206  fireChangeEvent();
207  }
208 
214  @Override
215  public final void addChangeListener(ChangeListener l) {
216  synchronized (listeners) {
217  listeners.add(l);
218  }
219  }
220 
226  @Override
227  public final void removeChangeListener(ChangeListener l) {
228  synchronized (listeners) {
229  listeners.remove(l);
230  }
231  }
232 
237  protected final void fireChangeEvent() {
238  Iterator<ChangeListener> it;
239  synchronized (listeners) {
240  it = new HashSet<>(listeners).iterator();
241  }
242  ChangeEvent ev = new ChangeEvent(this);
243  while (it.hasNext()) {
244  it.next().stateChanged(ev);
245  }
246  }
247 
254  @Override
255  public void readSettings(WizardDescriptor settings) {
256  // Start ingest if it hasn't already been started
257  startIngest();
258  settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, WizardDescriptor.CANCEL_OPTION});
259  if (imgAdded) {
260  getComponent().setStateFinished();
261  }
262  }
263 
264  void resetReadyToIngest() {
265  this.readyToIngest = false;
266  }
267 
268  void setIngestJobSettings(IngestJobSettings ingestSettings) {
269  showWarnings(ingestSettings);
270  this.readyToIngest = true;
271  this.ingestJobSettings = ingestSettings;
272  }
273 
280  @Override
281  public void storeSettings(WizardDescriptor settings) {
282  //why did we do this? -jm
283  // getComponent().resetInfoPanel();
284  }
285 
295  void addErrors(String errorString, boolean critical) {
296  getComponent().showErrors(errorString, critical);
297  }
298 
303  private void startIngest() {
304  if (!newContents.isEmpty() && readyToIngest && !ingested) {
305  ingested = true;
306  if (dsProcessor != null && !dsProcessor.supportsIngestStream()) {
307  IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettings);
308  }
309  setStateFinished();
310  }
311  }
312 
313  private static void showWarnings(IngestJobSettings ingestJobSettings) {
314  List<String> warnings = ingestJobSettings.getWarnings();
315  if (warnings.isEmpty() == false) {
316  StringBuilder warningMessage = new StringBuilder();
317  for (String warning : warnings) {
318  warningMessage.append(warning).append("\n");
319  }
320  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), warningMessage.toString());
321  }
322  }
323 
333  void startDataSourceProcessing(DataSourceProcessor dsp, Host selectedHost) {
334  if (dsProcessor == null) { //this can only be run once
335  final UUID dataSourceId = UUID.randomUUID();
336  newContents.clear();
337  cleanupTask = null;
338  dsProcessor = dsp;
339  new Thread(() -> {
340  // Add a cleanup task to interrupt the background process if the
341  // wizard exits while the background process is running.
342  cleanupTask = addImageAction.new CleanupTask() {
343  @Override
344  void cleanup() throws Exception {
345  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
346  cancelDataSourceProcessing(dataSourceId);
347  cancelled = true;
348  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
349  }
350  };
351 
352  cleanupTask.enable();
353 
354  try {
355  Case.getCurrentCaseThrows().notifyAddingDataSource(dataSourceId);
356  } catch (NoCurrentCaseException ex) {
357  Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
358  }
359 
360  DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
361  @Override
362  public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
363  dataSourceProcessorDone(dataSourceId, result, errList, contents);
364  }
365  };
366 
367  // Kick off the DSProcessor
368  if (dsProcessor.supportsIngestStream()) {
369  // Set readyToIngest to false to prevent the wizard from starting ingest a second time.
370  readyToIngest = false;
371  dsProcessor.runWithIngestStream(selectedHost, ingestJobSettings, getDSPProgressMonitorImpl(), cbObj);
372  } else {
373  dsProcessor.run(selectedHost, getDSPProgressMonitorImpl(), cbObj);
374  }
375  }).start();
376  setStateStarted();
377  }
378  }
379 
380  /*
381  * Cancels the data source processing - in case the users presses 'Cancel'
382  */
383  private void cancelDataSourceProcessing(UUID dataSourceId) {
384  dsProcessor.cancel();
385  }
386 
387  /*
388  * Callback for the data source processor. Invoked by the DSP on the EDT
389  * thread, when it finishes processing the data source.
390  */
391  private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
392  // disable the cleanup task
393  cleanupTask.disable();
394 
395  // Get attention for the process finish
396  // this caused a crash on OS X
397  if (PlatformUtil.isWindowsOS() == true) {
398  java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
399  }
400  AddImageWizardAddingProgressVisual panel = getComponent();
401  if (panel != null) {
402  Window w = SwingUtilities.getWindowAncestor(panel);
403  if (w != null) {
404  w.toFront();
405  }
406  }
407  // Tell the panel we're done
408  setStateFinished();
409 
410  //check the result and display to user
411  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS) {
412  getComponent().setProgressBarTextAndColor(
413  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text"), 100, Color.black);
414  } else {
415  getComponent().setProgressBarTextAndColor(
416  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.errs.text"), 100, Color.red);
417  }
418 
419  //if errors, display them on the progress panel
420  boolean critErr = false;
421  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
422  critErr = true;
423  }
424  for (String err : errList) {
425  // TBD: there probably should be an error level for each error
426  addErrors(err, critErr);
427  }
428  final Level level = critErr ? Level.SEVERE : Level.WARNING;
429  new Thread(() -> {
430  //log error messages as Severe if there was a critical error otherwise as Warning.
431  //logging performed off of UI thread
432  for (String err : errList) {
433  Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(level, "DatasourceID: {0} Error Message: {1}", new Object[]{dataSourceId.toString(), err});
434  }
435  //notify the UI of the new content added to the case
436  try {
437  if (!contents.isEmpty()) {
438  Case.getCurrentCaseThrows().notifyDataSourceAdded(contents.get(0), dataSourceId);
439  } else {
440  Case.getCurrentCaseThrows().notifyFailedAddingDataSource(dataSourceId);
441  }
442  } catch (NoCurrentCaseException ex) {
443  Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
444  }
445  }).start();
446 
447  if (!cancelled) {
448  newContents.clear();
449  newContents.addAll(contents);
450  setStateStarted();
451  startIngest();
452  } else {
453  cancelled = false;
454  }
455 
456  }
457 }

Copyright © 2012-2022 Basis Technology. Generated on: Tue Aug 1 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.