Autopsy  4.14.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  IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettings);
306  setStateFinished();
307  }
308  }
309 
310  private static void showWarnings(IngestJobSettings ingestJobSettings) {
311  List<String> warnings = ingestJobSettings.getWarnings();
312  if (warnings.isEmpty() == false) {
313  StringBuilder warningMessage = new StringBuilder();
314  for (String warning : warnings) {
315  warningMessage.append(warning).append("\n");
316  }
317  JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), warningMessage.toString());
318  }
319  }
320 
325  void startDataSourceProcessing(DataSourceProcessor dsp) {
326  if (dsProcessor == null) { //this can only be run once
327  final UUID dataSourceId = UUID.randomUUID();
328  newContents.clear();
329  cleanupTask = null;
330  readyToIngest = false;
331  dsProcessor = dsp;
332 
333  // Add a cleanup task to interrupt the background process if the
334  // wizard exits while the background process is running.
335  cleanupTask = addImageAction.new CleanupTask() {
336  @Override
337  void cleanup() throws Exception {
338  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
339  cancelDataSourceProcessing(dataSourceId);
340  cancelled = true;
341  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
342  }
343  };
344 
345  cleanupTask.enable();
346 
347  new Thread(() -> {
348  try {
349  Case.getCurrentCaseThrows().notifyAddingDataSource(dataSourceId);
350  } catch (NoCurrentCaseException ex) {
351  Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
352  }
353  }).start();
354  DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
355  @Override
356  public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
357  dataSourceProcessorDone(dataSourceId, result, errList, contents);
358  }
359  };
360 
361  setStateStarted();
362 
363  // Kick off the DSProcessor
364  dsProcessor.run(getDSPProgressMonitorImpl(), cbObj);
365  }
366  }
367 
368  /*
369  * Cancels the data source processing - in case the users presses 'Cancel'
370  */
371  private void cancelDataSourceProcessing(UUID dataSourceId) {
372  dsProcessor.cancel();
373  }
374 
375  /*
376  * Callback for the data source processor. Invoked by the DSP on the EDT
377  * thread, when it finishes processing the data source.
378  */
379  private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
380  // disable the cleanup task
381  cleanupTask.disable();
382 
383  // Get attention for the process finish
384  // this caused a crash on OS X
385  if (PlatformUtil.isWindowsOS() == true) {
386  java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
387  }
388  AddImageWizardAddingProgressVisual panel = getComponent();
389  if (panel != null) {
390  Window w = SwingUtilities.getWindowAncestor(panel);
391  if (w != null) {
392  w.toFront();
393  }
394  }
395  // Tell the panel we're done
396  setStateFinished();
397 
398  //check the result and display to user
399  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS) {
400  getComponent().setProgressBarTextAndColor(
401  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text"), 100, Color.black);
402  } else {
403  getComponent().setProgressBarTextAndColor(
404  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.errs.text"), 100, Color.red);
405  }
406 
407  //if errors, display them on the progress panel
408  boolean critErr = false;
409  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
410  critErr = true;
411  }
412  for (String err : errList) {
413  // TBD: there probably should be an error level for each error
414  addErrors(err, critErr);
415  }
416 
417  //notify the UI of the new content added to the case
418  new Thread(() -> {
419  try {
420  if (!contents.isEmpty()) {
421  Case.getCurrentCaseThrows().notifyDataSourceAdded(contents.get(0), dataSourceId);
422  } else {
423  Case.getCurrentCaseThrows().notifyFailedAddingDataSource(dataSourceId);
424  }
425  } catch (NoCurrentCaseException ex) {
426  Logger.getLogger(AddImageWizardAddingProgressVisual.class.getName()).log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
427  }
428  }).start();
429 
430  if (!cancelled) {
431  newContents.clear();
432  newContents.addAll(contents);
433  setStateStarted();
434  startIngest();
435  } else {
436  cancelled = false;
437  }
438 
439  }
440 }

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