Autopsy  4.5.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-2017 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 javax.swing.JOptionPane;
33 import javax.swing.SwingUtilities;
34 import javax.swing.event.ChangeEvent;
35 import javax.swing.event.ChangeListener;
36 import org.openide.WizardDescriptor;
37 import org.openide.util.HelpCtx;
38 import org.openide.util.Lookup;
39 import org.openide.util.NbBundle;
40 import org.openide.windows.WindowManager;
48 import org.sleuthkit.datamodel.Content;
49 
58 class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
59 
60  private boolean readyToIngest = false;
61  // task that will clean up the created database file if the wizard is cancelled before it finishes
62  private AddImageAction.CleanupTask cleanupTask;
63 
64  private final AddImageAction addImageAction;
65 
66  private DataSourceProcessor dsProcessor = null;
67  private boolean cancelled;
72  private boolean imgAdded = false;
73  private boolean ingested = false;
78  private AddImageWizardAddingProgressVisual component;
79  private final Set<ChangeListener> listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0
80  private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
81  private final DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl();
82  private IngestJobSettings ingestJobSettings;
83 
84  AddImageWizardAddingProgressPanel(AddImageAction action) {
85  this.addImageAction = action;
86  }
87 
88  DSPProgressMonitorImpl getDSPProgressMonitorImpl() {
89  return dspProgressMonitorImpl;
90  }
91 
93 
94  @Override
95  public void setIndeterminate(final boolean indeterminate) {
96  // update the progress bar asynchronously
97  EventQueue.invokeLater(new Runnable() {
98  @Override
99  public void run() {
100  getComponent().getProgressBar().setIndeterminate(indeterminate);
101  }
102  });
103  }
104 
105  @Override
106  public void setProgress(final int progress) {
107  // update the progress bar asynchronously
108  EventQueue.invokeLater(new Runnable() {
109  @Override
110  public void run() {
111  getComponent().getProgressBar().setValue(progress);
112  }
113  });
114  }
115 
116  @Override
117  public void setProgressText(final String text) {
118  // update the progress UI asynchronously
119  EventQueue.invokeLater(new Runnable() {
120  @Override
121  public void run() {
122  getComponent().setProgressMsgText(text);
123  }
124  });
125  }
126 
127  }
128 
139  @Override
140  public AddImageWizardAddingProgressVisual getComponent() {
141  if (component == null) {
142  component = new AddImageWizardAddingProgressVisual();
143  }
144  return component;
145  }
146 
153  @Override
154  public HelpCtx getHelp() {
155  // Show no Help button for this panel:
156  return HelpCtx.DEFAULT_HELP;
157  }
158 
165  @Override
166  public boolean isValid() {
167  // set the focus to the next button of the wizard dialog if it's enabled
168  if (imgAdded) {
169  Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton(
170  NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.isValid.focusNext"));
171  }
172 
173  return imgAdded;
174  }
175 
179  void setStateStarted() {
180  component.getProgressBar().setIndeterminate(true);
181  component.setProgressBarTextAndColor(
182  NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.stateStarted.progressBarText"), 0, Color.black);
183  }
184 
188  void setStateFinished() {
189  imgAdded = true;
190  getComponent().setStateFinished();
191  fireChangeEvent();
192  }
193 
199  @Override
200  public final void addChangeListener(ChangeListener l) {
201  synchronized (listeners) {
202  listeners.add(l);
203  }
204  }
205 
211  @Override
212  public final void removeChangeListener(ChangeListener l) {
213  synchronized (listeners) {
214  listeners.remove(l);
215  }
216  }
217 
222  protected final void fireChangeEvent() {
223  Iterator<ChangeListener> it;
224  synchronized (listeners) {
225  it = new HashSet<>(listeners).iterator();
226  }
227  ChangeEvent ev = new ChangeEvent(this);
228  while (it.hasNext()) {
229  it.next().stateChanged(ev);
230  }
231  }
232 
239  @Override
240  public void readSettings(WizardDescriptor settings) {
241  // Start ingest if it hasn't already been started
242  startIngest();
243  settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, WizardDescriptor.CANCEL_OPTION});
244  if (imgAdded) {
245  getComponent().setStateFinished();
246  }
247  }
248 
249  void resetReadyToIngest() {
250  this.readyToIngest = false;
251  }
252 
253  void setIngestJobSettings(IngestJobSettings ingestSettings) {
254  showWarnings(ingestSettings);
255  this.readyToIngest = true;
256  this.ingestJobSettings = ingestSettings;
257  }
258 
265  @Override
266  public void storeSettings(WizardDescriptor settings) {
267  //why did we do this? -jm
268  // getComponent().resetInfoPanel();
269  }
270 
280  void addErrors(String errorString, boolean critical) {
281  getComponent().showErrors(errorString, critical);
282  }
283 
288  private void startIngest() {
289  if (!newContents.isEmpty() && readyToIngest && !ingested) {
290  ingested = true;
291  IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettings);
292  setStateFinished();
293  }
294  }
295 
296  private static void showWarnings(IngestJobSettings ingestJobSettings) {
297  List<String> warnings = ingestJobSettings.getWarnings();
298  if (warnings.isEmpty() == false) {
299  StringBuilder warningMessage = new StringBuilder();
300  for (String warning : warnings) {
301  warningMessage.append(warning).append("\n");
302  }
303  JOptionPane.showMessageDialog(null, warningMessage.toString());
304  }
305  }
306 
311  void startDataSourceProcessing(DataSourceProcessor dsp) {
312  if (dsProcessor == null) { //this can only be run once
313  final UUID dataSourceId = UUID.randomUUID();
314  newContents.clear();
315  cleanupTask = null;
316  readyToIngest = false;
317  dsProcessor = dsp;
318 
319  // Add a cleanup task to interrupt the background process if the
320  // wizard exits while the background process is running.
321  cleanupTask = addImageAction.new CleanupTask() {
322  @Override
323  void cleanup() throws Exception {
324  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
325  cancelDataSourceProcessing(dataSourceId);
326  cancelled = true;
327  WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
328  }
329  };
330 
331  cleanupTask.enable();
332 
333  new Thread(() -> {
334  Case.getCurrentCase().notifyAddingDataSource(dataSourceId);
335  }).start();
336  DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() {
337  @Override
338  public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
339  dataSourceProcessorDone(dataSourceId, result, errList, contents);
340  }
341  };
342 
343  setStateStarted();
344 
345  // Kick off the DSProcessor
346  dsProcessor.run(getDSPProgressMonitorImpl(), cbObj);
347  }
348  }
349 
350  /*
351  * Cancels the data source processing - in case the users presses 'Cancel'
352  */
353  private void cancelDataSourceProcessing(UUID dataSourceId) {
354  dsProcessor.cancel();
355  }
356 
357  /*
358  * Callback for the data source processor. Invoked by the DSP on the EDT
359  * thread, when it finishes processing the data source.
360  */
361  private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errList, List<Content> contents) {
362  // disable the cleanup task
363  cleanupTask.disable();
364 
365  // Get attention for the process finish
366  // this caused a crash on OS X
367  if (PlatformUtil.isWindowsOS() == true) {
368  java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP!
369  }
370  AddImageWizardAddingProgressVisual panel = getComponent();
371  if (panel != null) {
372  Window w = SwingUtilities.getWindowAncestor(panel);
373  if (w != null) {
374  w.toFront();
375  }
376  }
377  // Tell the panel we're done
378  setStateFinished();
379 
380  //check the result and display to user
381  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS) {
382  getComponent().setProgressBarTextAndColor(
383  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text"), 100, Color.black);
384  } else {
385  getComponent().setProgressBarTextAndColor(
386  NbBundle.getMessage(this.getClass(), "AddImageWizardIngestConfigPanel.dsProcDone.errs.text"), 100, Color.red);
387  }
388 
389  //if errors, display them on the progress panel
390  boolean critErr = false;
391  if (result == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
392  critErr = true;
393  }
394  for (String err : errList) {
395  // TBD: there probably should be an error level for each error
396  addErrors(err, critErr);
397  }
398 
399  //notify the UI of the new content added to the case
400  new Thread(() -> {
401  if (!contents.isEmpty()) {
402  Case.getCurrentCase().notifyDataSourceAdded(contents.get(0), dataSourceId);
403  } else {
404  Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId);
405  }
406  }).start();
407 
408  if (!cancelled) {
409  newContents.clear();
410  newContents.addAll(contents);
411  setStateStarted();
412  startIngest();
413  } else {
414  cancelled = false;
415  }
416 
417  }
418 }

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