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

Copyright © 2012-2016 Basis Technology. Generated on: Mon May 7 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.