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

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.