From eda180e34fb0caeb70447d2d3ffed5223fc224ec Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 20 Jan 2016 17:30:29 -0500 Subject: [PATCH] Revert "Fix thread safety, clean up add data source wizard classes" This reverts commit b93d45fbf12824d7172ac6297ce4e6c24fbe1ed4. --- .../autopsy/casemodule/AddImageAction.java | 247 +++++++------ .../AddImageWizardAddingProgressPanel.java | 178 +++++----- .../AddImageWizardChooseDataSourcePanel.java | 177 +++++++--- .../AddImageWizardIngestConfigPanel.java | 325 +++++++----------- .../casemodule/AddImageWizardIterator.java | 95 ++--- .../autopsy/casemodule/Bundle.properties | 1 + .../autopsy/casemodule/Bundle_ja.properties | 1 + 7 files changed, 550 insertions(+), 474 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index 2bb2a58bd3..ee30eb8283 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2014 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,11 +21,13 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Component; import java.awt.Dialog; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.logging.Level; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.DialogDisplayer; @@ -35,91 +37,139 @@ import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CallableSystemAction; import org.openide.util.actions.Presenter; +import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Image; /** - * An action that adds a data source to the current case. + * The action to add an image to the current Case. This action should be + * disabled on creation and it will be enabled on new case creation or case + * opened. * - * RC: This action needs to be enabled and disabled as cases are opened and - * closed. Currently this is done using - * CallableSystemAction.get(AddImageAction.class).setEnabled(). + * @author jantonius */ +// TODO: need annotation because there's a "Lookup.getDefault().lookup(AddImageAction.class)" +// used in AddImageWizardPanel1 (among other places). It really shouldn't be done like that. +@ServiceProvider(service = AddImageAction.class) public final class AddImageAction extends CallableSystemAction implements Presenter.Toolbar { - private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); - private final ChangeSupport cleanupSupport; - private final JButton toolbarButton; + // Keys into the WizardDescriptor properties that pass information between stages of the wizard + // : + // String: time zone that the image is from + static final String TIMEZONE_PROP = "timeZone"; //NON-NLS + // String[]: array of paths to each data source selected + static final String DATASOURCEPATH_PROP = "dataSrcPath"; //NON-NLS + // String data source type selected + static final String DATASOURCETYPE_PROP = "dataSrcType"; //NON-NLS + // CleanupTask: task to clean up the database file if wizard errors/is cancelled after it is created + static final String IMAGECLEANUPTASK_PROP = "finalFileCleanup"; //NON-NLS + // int: the next availble id for a new image + static final String IMAGEID_PROP = "imageId"; //NON-NLS + // AddImageProcess: the next availble id for a new image + static final String PROCESS_PROP = "process"; //NON-NLS + // boolean: whether or not to lookup files in the hashDB + static final String LOOKUPFILES_PROP = "lookupFiles"; //NON-NLS + // boolean: whether or not to skip processing orphan files on FAT filesystems + static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS + + static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); + private WizardDescriptor wizardDescriptor; private WizardDescriptor.Iterator iterator; + private Dialog dialog; + private JButton toolbarButton = new JButton(); /** - * Constructs an action that adds a data source to the current case. + * The constructor for AddImageAction class */ public AddImageAction() { - cleanupSupport = new ChangeSupport(this); - putValue(Action.NAME, NbBundle.getMessage(AddImageAction.class, "CTL_AddImage")); - toolbarButton = new JButton(); - toolbarButton.addActionListener(AddImageAction.this::actionPerformed); - setEnabled(false); + putValue(Action.NAME, NbBundle.getMessage(AddImageAction.class, "CTL_AddImage")); // set the action Name + + // set the action for the toolbar button + toolbarButton.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + AddImageAction.this.actionPerformed(e); + } + }); + + this.setEnabled(false); // disable this action class } /** - * Displays the first panel of the add data source wizard. + * Pop-up the "Add Image" wizard panel. * - * @param notUsed An action event, may be null. + * @param e */ @Override - public void actionPerformed(ActionEvent notUsed) { - /* - * If ingest is running, confirm that the user wants to add another data - * source at this time, instead of waiting for the current ingest job to - * complete. - */ + public void actionPerformed(ActionEvent e) { if (IngestManager.getInstance().isIngestRunning()) { - if (JOptionPane.showConfirmDialog(null, - NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg"), - NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.title"), + final String msg = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg"); + if (JOptionPane.showConfirmDialog(null, msg, + NbBundle.getMessage(this.getClass(), + "AddImageAction.ingestConfig.ongoingIngest.title"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.NO_OPTION) { return; } } - /* - * Construct and display the wizard. - */ - iterator = new AddImageWizardIterator(); + iterator = new AddImageWizardIterator(this); wizardDescriptor = new WizardDescriptor(iterator); wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "AddImageAction.wizard.title")); - Dialog dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); + wizardDescriptor.putProperty(NAME, e); + + if (dialog != null) { + dialog.setVisible(false); // hide the old one + } + dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); dialog.setVisible(true); dialog.toFront(); - /* - * Run any registered cleanup tasks by firing a change event. This will - * cause the stateChanged method of any implementations of the inner, - * abstract CleanupTask class to call their cleanup methods (assuming - * they have not done an override of stateChanged), after which the - * CleanupTasks are unregistered. - * - * RC: This is a convoluted and error-prone way to implement clean up. - * Fortunately, it is confined to this package. - */ - cleanupSupport.fireChange(); + // Do any cleanup that needs to happen (potentially: stopping the + //add-image process, reverting an image) + runCleanupTasks(); } /** - * @inheritDoc + * Closes the current dialog and wizard, and opens a new one. Used in the + * "Add another image" action on the last panel + */ + void restart() { + // Simulate clicking finish for the current dialog + wizardDescriptor.setValue(WizardDescriptor.FINISH_OPTION); + dialog.setVisible(false); + + // let the previous call to AddImageAction.actionPerformed() finish up + // after the wizard, this will run when its it's done + final Runnable r = new Runnable() { + @Override + public void run() { + actionPerformed(null); + } + }; + + SwingUtilities.invokeLater(r); + } + + public interface IndexImageTask { + + void runTask(Image newImage); + } + + /** + * This method does nothing. Use the "actionPerformed(ActionEvent e)" + * instead of this method. */ @Override public void performAction() { - actionPerformed(null); } /** - * @inheritDoc + * Gets the name of this action. This may be presented as an item in a menu. + * + * @return actionName */ @Override public String getName() { @@ -127,7 +177,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen } /** - * @inheritDoc + * Gets the HelpCtx associated with implementing object + * + * @return HelpCtx or HelpCtx.DEFAULT_HELP */ @Override public HelpCtx getHelpCtx() { @@ -135,7 +187,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen } /** - * @inheritDoc + * Returns the toolbar component of this action + * + * @return component the toolbar button */ @Override public Component getToolbarPresenter() { @@ -146,7 +200,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen } /** - * @inheritDoc + * Set this action to be enabled/disabled + * + * @param value whether to enable this action or not */ @Override public void setEnabled(boolean value) { @@ -155,80 +211,68 @@ public final class AddImageAction extends CallableSystemAction implements Presen } /** - * Does nothing, do not use. + * Set the focus to the button of the given name on this wizard dialog. * - * @deprecated Classes in this package may call requestFocusForWizardButton - * instead. + * Note: the name of the buttons that available are "Next >", "< Back", + * "Cancel", and "Finish". If you change the name of any of those buttons, + * use the latest name instead. + * + * @param buttonText the text of the button */ - @Deprecated public void requestFocusButton(String buttonText) { - } - - /** - * Requests focus for an add data source wizard button. - * - * @param buttonText The text of the button. - */ - void requestFocusForWizardButton(String buttonText) { - for (Object wizardButton : wizardDescriptor.getOptions()) { - JButton button = (JButton) wizardButton; - if (button.getText().equals(buttonText)) { - button.setDefaultCapable(true); - button.requestFocus(); + // get all buttons on this wizard panel + Object[] wizardButtons = wizardDescriptor.getOptions(); + for (int i = 0; i < wizardButtons.length; i++) { + JButton tempButton = (JButton) wizardButtons[i]; + if (tempButton.getText().equals(buttonText)) { + tempButton.setDefaultCapable(true); + tempButton.requestFocus(); } } } /** - * Enabled instances of this class are called to do clean up after the add - * data source wizard is closed. The instances are disabled after the - * cleanUp method is called. Implementations should not override - * stateChanged, and should not re-enable themselves after cleanUp is - * called. To stop cleanUp being called, call disable before the wizard is - * dismissed. + * Run and clear any cleanup tasks for wizard closing that might be + * registered. This should be run even when the wizard exits cleanly, so + * that no cleanup actions remain the next time the wizard is run. + */ + private void runCleanupTasks() { + cleanupSupport.fireChange(); + } + + ChangeSupport cleanupSupport = new ChangeSupport(this); + + /** + * Instances of this class implement the cleanup() method to run cleanup + * code when the wizard exits. * - * Instances must be constructed using a reference to an AddImageAction - * object because this is a non-static inner class. + * After enable() has been called on an instance it will run once after the + * wizard closes (on both a cancel and a normal finish). * - * RC: This is a convoluted and error-prone way to implement clean up. - * Fortunately, it is confined to this package. + * If disable() is called before the wizard exits, the task will not run. */ abstract class CleanupTask implements ChangeListener { @Override public void stateChanged(ChangeEvent e) { - /* - * actionPerformed fires this event after the add data source wizard - * is closed. - */ + // fired by AddImageAction.runCleanupTasks() after the wizard closes try { cleanup(); } catch (Exception ex) { - logger.log(Level.SEVERE, "Error cleaning in add data source wizard clean up task", ex); //NON-NLS + Logger logger = Logger.getLogger(this.getClass().getName()); + logger.log(Level.WARNING, "Error cleaning up from wizard.", ex); //NON-NLS } finally { - /* - * Clean up tasks should only be done exactly once. - */ - disable(); + disable(); // cleanup tasks should only run once. } } /** - * Adds this task to the list of tasks to be done when the wizard - * closes. + * Add task to the enabled list to run when the wizard closes. */ - void enable() { + public void enable() { cleanupSupport.addChangeListener(this); } - /** - * Removes this task from the list of tasks to be done when the wizard - * closes. - */ - void disable() { - cleanupSupport.removeChangeListener(this); - } - /** * Performs cleanup action when called * @@ -236,12 +280,11 @@ public final class AddImageAction extends CallableSystemAction implements Presen */ abstract void cleanup() throws Exception; + /** + * Remove task from the enabled list. + */ + public void disable() { + cleanupSupport.removeChangeListener(this); + } } - - @Deprecated - public interface IndexImageTask { - - void runTask(Image newImage); - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index f64f41091d..7204664d2f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2014 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,97 +20,105 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Color; import java.awt.EventQueue; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; -import org.openide.util.ChangeSupport; import org.openide.util.HelpCtx; +import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; /** - * The third and final panel of the add data source wizard. The visual component - * of this panel displays a progress bar that is managed by the previous panel - * and the data source processor. + * The final panel of the add image wizard. It displays a progress bar and + * status updates. + * + * All the real work is kicked off in the previous panel: + * {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m + * -jm) */ -// All the real work is kicked off in the previous panel: -// {@link AddImageWizardIngestConfigPanel} (which is a bit weird if you ask m -// -jm) -final class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePanel { +class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePanel { - private final ChangeSupport changeSupport; - private final DSPProgressMonitorImpl dspProgressMonitor = new DSPProgressMonitorImpl(); + /** + * flag to indicate that the image adding process is finished and this panel + * is completed(valid) + */ + private boolean imgAdded = false; + /** + * The visual component that displays this panel. If you need to access the + * component from this class, just use getComponent(). + */ private AddImageWizardAddingProgressVisual component; - private boolean dataSourceAdded = false; + private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 - /** - * Constructs an instance of the third and final panel of the add data - * source wizard. - */ - AddImageWizardAddingProgressPanel() { - changeSupport = new ChangeSupport(this); + private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); + + public DSPProgressMonitorImpl getDSPProgressMonitorImpl() { + return dspProgressMonitorImpl; } - /** - * Gets the data source progress monitor. Allows the previous panel to hand - * off the progress monitor to the data source processor. - */ - DSPProgressMonitorImpl getDSPProgressMonitor() { - return dspProgressMonitor; - } - - /** - * A data source processor progress monitor that acts as a bridge between - * the data source processor started by the previous panel and the progress - * bar displayed by the visual component of this panel. - */ private class DSPProgressMonitorImpl implements DataSourceProcessorProgressMonitor { @Override public void setIndeterminate(final boolean indeterminate) { - EventQueue.invokeLater(() -> { - getComponent().getProgressBar().setIndeterminate(indeterminate); + // update the progress bar asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setIndeterminate(indeterminate); + } }); } @Override public void setProgress(final int progress) { // update the progress bar asynchronously - EventQueue.invokeLater(() -> { - getComponent().getProgressBar().setValue(progress); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setValue(progress); + } }); } @Override public void setProgressText(final String text) { // update the progress UI asynchronously - EventQueue.invokeLater(() -> { - getComponent().setProgressMsgText(text); + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().setProgressMsgText(text); + } }); } } /** - * Gets the visual component for the panel. In this template, the component + * Get the visual component for the panel. In this template, the component * is kept separate. This can be more efficient: if the wizard is created * but never displayed, or not all panels are displayed, it is better to * create only those which really need to be visible. * - * @return The UI component of this wizard panel. + * It also separates the view from the control - jm + * + * @return component the UI component of this wizard panel */ @Override public AddImageWizardAddingProgressVisual getComponent() { - if (null == component) { + if (component == null) { component = new AddImageWizardAddingProgressVisual(); } return component; } /** - * Gets the help for this panel. When the panel is active, this is used as - * the help for the wizard dialog. + * Help for this panel. When the panel is active, this is used as the help + * for the wizard dialog. * - * @return The help for this panel + * @return HelpCtx.DEFAULT_HELP the help for this panel */ @Override public HelpCtx getHelp() { @@ -126,12 +134,17 @@ final class AddImageWizardAddingProgressPanel implements WizardDescriptor.Finish */ @Override public boolean isValid() { - return dataSourceAdded; + // set the focus to the next button of the wizard dialog if it's enabled + if (imgAdded) { + Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton( + NbBundle.getMessage(this.getClass(), "AddImageWizardAddingProgressPanel.isValid.focusNext")); + } + + return imgAdded; } /** - * Makes the progress bar of the visual component of this panel indicate - * that the data source processor is running. + * Updates the UI to display the add image process has begun. */ void setStateStarted() { component.getProgressBar().setIndeterminate(true); @@ -140,85 +153,94 @@ final class AddImageWizardAddingProgressPanel implements WizardDescriptor.Finish } /** - * Makes the progress bar of the visual component of this panel indicate - * that the data source processor is not running. + * Updates the UI to display the add image process is over. */ void setStateFinished() { - dataSourceAdded = true; + imgAdded = true; getComponent().setStateFinished(); fireChangeEvent(); } /** - * @inheritDoc5 + * Adds a listener to changes of the panel's validity. + * + * @param l the change listener to add */ @Override - public final void addChangeListener(ChangeListener listener) { - changeSupport.addChangeListener(listener); + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } } /** - * @inheritDoc + * Removes a listener to changes of the panel's validity. + * + * @param l the change listener to move */ @Override - public final void removeChangeListener(ChangeListener listener) { - changeSupport.removeChangeListener(listener); + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } } /** - * @inheritDoc + * This method is auto-generated. It seems that this method is used to + * listen to any change in this wizard panel. */ protected final void fireChangeEvent() { - changeSupport.fireChange(); + Iterator it; + synchronized (listeners) { + it = new HashSet(listeners).iterator(); + } + ChangeEvent ev = new ChangeEvent(this); + while (it.hasNext()) { + it.next().stateChanged(ev); + } } /** - * Provides the wizard panel with the current data--either the default data - * or already-modified settings, if the user used the previous and/or next - * buttons. This method can be called multiple times on one instance of - * WizardDescriptor.Panel. + * Load the image locations from the WizardDescriptor settings object, and + * the * - * @param settings The settings. + * @param settings the setting to be read from */ @Override public void readSettings(WizardDescriptor settings) { settings.setOptions(new Object[]{WizardDescriptor.PREVIOUS_OPTION, WizardDescriptor.NEXT_OPTION, WizardDescriptor.FINISH_OPTION, WizardDescriptor.CANCEL_OPTION}); - if (dataSourceAdded) { + if (imgAdded) { getComponent().setStateFinished(); } } /** - * Provides the wizard panel with the opportunity to update the settings - * with its current customized state. Rather than updating its settings with - * every change in the GUI, it should collect them, and then only save them - * when requested to by this method. This method can be called multiple - * times on one instance of WizardDescriptor.Panel. + * this doesn't appear to store anything? plus, there are no settings in + * this panel -jm * * @param settings the setting to be stored to */ @Override public void storeSettings(WizardDescriptor settings) { + //why did we do this? -jm + // getComponent().resetInfoPanel(); } /** - * Displays an error message from the data source processor for the data - * source being added. + * forward errors to visual component * - * @param errorString The error message to be displayed - * @param critical True if this is a critical error + * should this be modified to handle a list of errors? -jm + * + * + * @param errorString the error string to be displayed + * @param critical true if this is a critical error */ - // Should this be modified to handle a list of errors? -jm - void displayDataSourceProcessorError(String errorString, boolean critical) { + void addErrors(String errorString, boolean critical) { getComponent().showErrors(errorString, critical); } - /** - * @inheritDoc - */ @Override public boolean isFinishPanel() { return true; } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index ba7d7fb7ba..88762ba96a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,43 +20,55 @@ package org.sleuthkit.autopsy.casemodule; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; +import org.openide.util.Lookup; import org.openide.windows.WindowManager; import java.awt.Cursor; -import org.openide.util.ChangeSupport; -import org.openide.util.actions.CallableSystemAction; /** - * The first panel of the add data source wizard. The visual component of this - * panel allows a user to select data sources to add to the current case. + * The "Add Image" wizard panel1 handling the logic of selecting image file(s) + * to add to Case, and pick the time zone. */ -final class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel, PropertyChangeListener { - - private AddImageWizardChooseDataSourceVisual component; - private final ChangeSupport changeSupport; - private boolean nextButtonIsEnabled = false; +class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel, PropertyChangeListener { /** - * Constructs an instance of the first panel of the add data source wizard. + * The visual component that displays this panel. If you need to access the + * component from this class, just use getComponent(). */ - AddImageWizardChooseDataSourcePanel() { - changeSupport = new ChangeSupport(this); + private AddImageWizardAddingProgressPanel progressPanel; + private AddImageWizardChooseDataSourceVisual component; + private boolean isNextEnable = false; + private static final String PROP_LASTDATASOURCE_PATH = "LBL_LastDataSource_PATH"; //NON-NLS + private static final String PROP_LASTDATASOURCE_TYPE = "LBL_LastDataSource_TYPE"; //NON-NLS + // paths to any set hash lookup databases (can be null) + private String NSRLPath, knownBadPath; + + AddImageWizardChooseDataSourcePanel(AddImageWizardAddingProgressPanel proPanel) { + + this.progressPanel = proPanel; + } /** - * Gets the visual component for the panel. The component is kept separate. - * This can be more efficient: if the wizard is created but never displayed, - * or not all panels are displayed, it is better to create only those which - * really need to be visible. + * Get the visual component for the panel. In this template, the component + * is kept separate. This can be more efficient: if the wizard is created + * but never displayed, or not all panels are displayed, it is better to + * create only those which really need to be visible. * - * @return The UI component of this wizard panel. + * @return component the UI component of this wizard panel */ @Override public AddImageWizardChooseDataSourceVisual getComponent() { - if (null == component) { + if (component == null) { WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); component = new AddImageWizardChooseDataSourceVisual(this); } @@ -65,103 +77,156 @@ final class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Pane } /** - * Gets the help for this panel. When the panel is active, this is used as - * the help for the wizard dialog. + * Help for this panel. When the panel is active, this is used as the help + * for the wizard dialog. * - * @return The help for this panel + * @return HelpCtx.DEFAULT_HELP the help for this panel */ @Override public HelpCtx getHelp() { // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; + // If you have context help: + // return new HelpCtx(SampleWizardPanel1.class); } /** + * Tests whether the panel is finished and it is safe to proceed to the next + * one. If the panel is valid, the "Next" button will be enabled. * - * Tests whether or not the panel is finished. If the panel is valid, the - * "Finish" button will be enabled. - * - * @return True or false. + * @return boolean true if all the fields are correctly filled, false + * otherwise */ @Override public boolean isValid() { - // If it is always OK to press Next or Finish, then: - // return true; - // If it depends on some condition (form filled out...), then: - // return someCondition(); - // and when this condition changes (last form field filled in...) then: - // fireChangeEvent(); - /* - * When it is valid, the visual component calls enableNextButton to set - * this flag. - */ - return nextButtonIsEnabled; + return isNextEnable; } /** - * Moves the keyboard focus to the next button of the wizard. + * Move the keyboard focus to the next button */ void moveFocusToNext() { - if (nextButtonIsEnabled) { - CallableSystemAction.get(AddImageAction.class).requestFocusForWizardButton( + // set the focus to the next button of the wizard dialog if it's enabled + if (isNextEnable) { + Lookup.getDefault().lookup(AddImageAction.class).requestFocusButton( NbBundle.getMessage(this.getClass(), "AddImageWizardChooseDataSourcePanel.moveFocusNext")); } } /** - * Enables the "Next" button and fires a change event to update the UI. + * Enable the "Next" button and fireChangeEvent to update the GUI * - * @param isEnabled True if next button should be enabled, false otherwise. + * @param isEnabled true if next button can be enabled, false otherwise */ - void enableNextButton(boolean isEnabled) { - nextButtonIsEnabled = isEnabled; + public void enableNextButton(boolean isEnabled) { + isNextEnable = isEnabled; fireChangeEvent(); } + private final Set listeners = new HashSet(1); // or can use ChangeSupport in NB 6.0 /** - * @inheritDoc + * Adds a listener to changes of the panel's validity. + * + * @param l the change listener to add */ @Override - public final void addChangeListener(ChangeListener listener) { - changeSupport.addChangeListener(listener); + public final void addChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.add(l); + } } /** - * @inheritDoc + * Removes a listener to changes of the panel's validity. + * + * @param l the change listener to move */ @Override - public final void removeChangeListener(ChangeListener listener) { - changeSupport.removeChangeListener(listener); + public final void removeChangeListener(ChangeListener l) { + synchronized (listeners) { + listeners.remove(l); + } } /** - * @inheritDoc + * This method is auto-generated. It seems that this method is used to + * listen to any change in this wizard panel. */ protected final void fireChangeEvent() { - changeSupport.fireChange(); + Iterator it; + synchronized (listeners) { + it = new HashSet(listeners).iterator(); + } + ChangeEvent ev = new ChangeEvent(this); + while (it.hasNext()) { + it.next().stateChanged(ev); + } } + // You can use a settings object to keep track of state. Normally the + // settings object will be the WizardDescriptor, so you can use + // WizardDescriptor.getProperty & putProperty to store information entered + // by the user. /** * Provides the wizard panel with the current data--either the default data * or already-modified settings, if the user used the previous and/or next * buttons. This method can be called multiple times on one instance of - * WizardDescriptor.Panel. + * WizardDescriptor.Panel. s * - * @param settings The settings. + * @param settings the setting to be read from */ @Override public void readSettings(WizardDescriptor settings) { + + //reset settings if supports it + //getComponent().reset(); + // Prepopulate the image directory from the properties file + try { + + // Load hash database settings, enable or disable the checkbox + this.NSRLPath = null; + this.knownBadPath = null; + //JCheckBox lookupFilesCheckbox = component.getLookupFilesCheckbox(); + //lookupFilesCheckbox.setSelected(false); + //lookupFilesCheckbox.setEnabled(this.NSRLPath != null || this.knownBadPath != null); + + // If there is a process object in the settings, revert it and remove it from the settings + AddImageAction.CleanupTask cleanupTask = (AddImageAction.CleanupTask) settings.getProperty(AddImageAction.IMAGECLEANUPTASK_PROP); + if (cleanupTask != null) { + try { + cleanupTask.cleanup(); + } catch (Exception ex) { + Logger logger = Logger.getLogger(AddImageWizardChooseDataSourcePanel.class.getName()); + logger.log(Level.WARNING, "Error cleaning up image task", ex); //NON-NLS + } finally { + cleanupTask.disable(); + } + } + } catch (Exception e) { + } + } /** - * @inheritDoc + * Provides the wizard panel with the opportunity to update the settings + * with its current customized state. Rather than updating its settings with + * every change in the GUI, it should collect them, and then only save them + * when requested to by this method. This method can be called multiple + * times on one instance of WizardDescriptor.Panel. + * + * @param settings the setting to be stored to */ @Override public void storeSettings(WizardDescriptor settings) { + + return; } /** - * @inheritDoc + * The "listener" for any property change in this panel. Any property + * changes will invoke the "fireChangeEvent()" method. + * + * @param evt the property change event */ @Override public void propertyChange(PropertyChangeEvent evt) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 5d83ec3994..46114c52fb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2015 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,9 +31,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; -import org.openide.util.ChangeSupport; import org.openide.util.HelpCtx; -import org.openide.util.actions.CallableSystemAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @@ -42,108 +40,80 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettingsPanel; import org.sleuthkit.autopsy.ingest.IngestManager; /** - * The second panel of the add data source wizard. The visual component of this - * panel allows a user to configure the ingest modules for the ingest job for - * the data source, and this panel both runs the data source processor and - * starts the ingest job. + * second panel of add image wizard, allows user to configure ingest modules. + * + * TODO: review this for dead code. think about moving logic of adding image to + * 3rd panel( {@link AddImageWizardAddingProgressPanel}) separate class -jm */ -// JM: Think about moving the logic of adding image to the 3rd panel -// ( {@link AddImageWizardAddingProgressPanel}) -final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { +class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - private final AddImageWizardChooseDataSourcePanel selectDataSourcePanel; - private final AddImageWizardAddingProgressPanel progressPanel; - private final ChangeSupport changeSupport; - private final List newContents; private final IngestJobSettingsPanel ingestJobSettingsPanel; - private Component component; - private volatile boolean ingestModulesConfigured; - private volatile boolean ingestJobStarted; - private AddImageAction.CleanupTask cleanupTask; - private DataSourceProcessor dsProcessor; /** - * Constructs an instance of The second panel of the add data source wizard. - * The visual component of this panel allows a user to configure the ingest - * modules for the ingest job for the data source. - * - * @param selectDataSourcePanel The second panel of the add data source - * wizard. - * @param progressPanel The third panel of the data source wizard. + * The visual component that displays this panel. If you need to access the + * component from this class, just use getComponent(). */ - AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel selectDataSourcePanel, AddImageWizardAddingProgressPanel progressPanel) { - this.selectDataSourcePanel = selectDataSourcePanel; - this.progressPanel = progressPanel; - changeSupport = new ChangeSupport(this); + private Component component = null; - /* - * Create a collection to receive the Content objects returned by the - * data source processor. - */ - newContents = Collections.synchronizedList(new ArrayList()); + private final List newContents = Collections.synchronizedList(new ArrayList()); + private boolean ingested = false; + private boolean readyToIngest = false; + + // task that will clean up the created database file if the wizard is cancelled before it finishes + private AddImageAction.CleanupTask cleanupTask; + + private final AddImageAction addImageAction; + + private final AddImageWizardAddingProgressPanel progressPanel; + private final AddImageWizardChooseDataSourcePanel dataSourcePanel; + + private DataSourceProcessor dsProcessor; + + AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) { + this.addImageAction = action; + this.progressPanel = proPanel; + this.dataSourcePanel = dsPanel; - /* - * Get the ingest job settings for the add data source wizard context - * and use them to create an ingest module configuration panel. - */ IngestJobSettings ingestJobSettings = new IngestJobSettings(AddImageWizardIngestConfigPanel.class.getCanonicalName()); - showIngestModuleConfigurationWarnings(ingestJobSettings); - ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); - - /* - * This flag is used to stop the data source processing thread from - * starting the ingest job before the user has finished configuring the - * ingest modules. It is only set in the EDT. - */ - ingestModulesConfigured = false; - - /* - * This flag is required because because the storeSettings method is - * currently called twice during the course of executing the add data - * source wizard, whether invoked from the new case wizard or - * independently. This means that the tryStartDataSourceIngestJob method - * gets called three times: once when the data source processor - * completes, and twice when the two storeSettings calls are made. - * - * TODO (AUT-1864): Figure out whether storeSettings is always called - * twice by NetBeans, or the extra call is due to an Autopsy bug. - */ - ingestJobStarted = false; + showWarnings(ingestJobSettings); + this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); } /** - * Gets the visual component for the panel. In this template, the component + * Get the visual component for the panel. In this template, the component * is kept separate. This can be more efficient: if the wizard is created * but never displayed, or not all panels are displayed, it is better to * create only those which really need to be visible. * - * @return The UI component of this wizard panel. + * @return component the UI component of this wizard panel */ @Override public Component getComponent() { - if (null == component) { + if (component == null) { component = new AddImageWizardIngestConfigVisual(this.ingestJobSettingsPanel); } return component; } /** - * Gets the help for this panel. When the panel is active, this is used as - * the help for the wizard dialog. + * Help for this panel. When the panel is active, this is used as the help + * for the wizard dialog. * - * @return The help for this panel + * @return HelpCtx.DEFAULT_HELP the help for this panel */ @Override public HelpCtx getHelp() { // Show no Help button for this panel: return HelpCtx.DEFAULT_HELP; + // If you have context help: + // return new HelpCtx(SampleWizardPanel1.class); } /** - * Tests whether or not the panel is finished. If the panel is valid, the - * "Finish" button will be enabled. + * Tests whether the panel is finished. If the panel is valid, the "Finish" + * button will be enabled. * - * @return True or false. + * @return true the finish button should be always enabled at this point */ @Override public boolean isValid() { @@ -153,53 +123,52 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel warnings = ingestJobSettings.getWarnings(); if (warnings.isEmpty() == false) { StringBuilder warningMessage = new StringBuilder(); @@ -248,78 +204,76 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - /* - * Publish a failed adding data source event, using the - * event id associated with the adding data source event. - */ - Case.getCurrentCase().notifyFailedAddingDataSource(addDataSourceEventId); - }).start(); - dsProcessor.cancel(); + cancelDataSourceProcessing(dataSourceId); } }; + cleanupTask.enable(); - /* - * Publish an adding data source event. - */ + // get the selected DSProcessor + dsProcessor = dataSourcePanel.getComponent().getCurrentDSProcessor(); + new Thread(() -> { - Case.getCurrentCase().notifyAddingDataSource(addDataSourceEventId); + Case.getCurrentCase().notifyAddingDataSource(dataSourceId); }).start(); - - /* - * Notify the progress panel for this wizard that data source processing - * is starting. - */ - progressPanel.setStateStarted(); - - /* - * Get the data source processor the user selected and start it. - */ - dsProcessor = selectDataSourcePanel.getComponent().getCurrentDSProcessor(); - DataSourceProcessorCallback callback = new DataSourceProcessorCallback() { + DataSourceProcessorCallback cbObj = new DataSourceProcessorCallback() { @Override public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { - dataSourceProcessorDone(addDataSourceEventId, result, errList, contents); + dataSourceProcessorDone(dataSourceId, result, errList, contents); } + }; - dsProcessor.run(progressPanel.getDSPProgressMonitor(), callback); + + progressPanel.setStateStarted(); + + // Kick off the DSProcessor + dsProcessor.run(progressPanel.getDSPProgressMonitorImpl(), cbObj); + } /* - * The callback for the data source processor to invoke when it finishes. + * Cancels the data source processing - in case the users presses 'Cancel' */ - private void dataSourceProcessorDone(UUID addDataSourceEventId, DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { - /* - * Disable the clean up task. - */ + private void cancelDataSourceProcessing(UUID dataSourceId) { + new Thread(() -> { + Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); + }).start(); + dsProcessor.cancel(); + } + + /* + * Callback for the data source processor. Invoked by the DSP on the EDT + * thread, when it finishes processing the data source. + */ + private void dataSourceProcessorDone(UUID dataSourceId, DataSourceProcessorCallback.DataSourceProcessorResult result, List errList, List contents) { + // disable the cleanup task cleanupTask.disable(); - /* - * Get the user's attention. - * - * RC: Is this really necessary? - */ - java.awt.Toolkit.getDefaultToolkit().beep(); + // Get attention for the process finish + java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); if (panel != null) { Window w = SwingUtilities.getWindowAncestor(panel); @@ -327,12 +281,10 @@ final class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { if (!newContents.isEmpty()) { - Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), addDataSourceEventId); + Case.getCurrentCase().notifyDataSourceAdded(newContents.get(0), dataSourceId); } else { - Case.getCurrentCase().notifyFailedAddingDataSource(addDataSourceEventId); + Case.getCurrentCase().notifyFailedAddingDataSource(dataSourceId); } }).start(); - /* - * Try starting the ingest job for this data source. If the data source - * processor finished before the user finished configuring the ingest - * modules, the job will not be started yet. - */ - tryStartIngestJob(); - } + // Start ingest if we can + progressPanel.setStateStarted(); + startIngest(); - /** - * Starts an ingest job for the data source, but only if the data source - * processor has been run and has produced content, and the ingest modules - * are configured. - */ - synchronized private void tryStartIngestJob() { - if (!newContents.isEmpty() && ingestModulesConfigured && !ingestJobStarted) { - ingestJobStarted = true; // See contructor for comment on this flag. - IngestManager.getInstance().queueIngestJob(newContents, ingestJobSettingsPanel.getSettings()); - } } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java index 034f3e5391..72f778e9de 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIterator.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,52 +28,52 @@ import org.openide.WizardDescriptor; import org.openide.util.NbBundle; /** - * The iterator for the add data source wizard panels. + * The iterator class for the "Add Image" wizard panel. This class is used to + * iterate on the sequence of panels of the "Add Image" wizard panel. */ -final class AddImageWizardIterator implements WizardDescriptor.Iterator { +class AddImageWizardIterator implements WizardDescriptor.Iterator { private int index = 0; private List> panels; + private AddImageAction action; + + AddImageWizardIterator(AddImageAction action) { + this.action = action; + } /** - * Lazily create the panels for the add data source wizard. + * Initialize panels representing individual wizard's steps and sets various + * properties for them influencing wizard appearance. */ private List> getPanels() { - if (null == panels) { - panels = new ArrayList<>(); + if (panels == null) { + panels = new ArrayList>(); - /* - * Create the wizard panels. The first panel is used to select a - * data source. The second panel is used to configure the ingest - * modules. The third panel has a progress bar that tracks progress - * as the Sleuthkit layer adds the data source to the case database. - */ - AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(); AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(); - AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, progressPanel); + + AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel); + AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel); + panels.add(dsPanel); panels.add(ingestConfigPanel); panels.add(progressPanel); - /* - * Set the appearance of the visual components of the panels. - */ String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { - Component visualComponent = panels.get(i).getComponent(); - // Default step name to component name. - steps[i] = visualComponent.getName(); - if (visualComponent instanceof JComponent) { - JComponent jc = (JComponent) visualComponent; - // Set step number. - jc.putClientProperty("WizardPanel_contentSelectedIndex", i); - // Sets step name. + Component c = panels.get(i).getComponent(); + // Default step name to component name of panel. + steps[i] = c.getName(); + if (c instanceof JComponent) { // assume Swing components + JComponent jc = (JComponent) c; + // Sets step number of a component + jc.putClientProperty("WizardPanel_contentSelectedIndex", new Integer(i)); + // Sets steps names for a panel jc.putClientProperty("WizardPanel_contentData", steps); - // Turn on subtitle creation. + // Turn on subtitle creation on each step jc.putClientProperty("WizardPanel_autoWizardStyle", Boolean.TRUE); - // Show steps on the left side, with image in the background. + // Show steps on the left side with the image on the background jc.putClientProperty("WizardPanel_contentDisplayed", Boolean.TRUE); - // Turn on step numbering. + // Turn on numbering of all steps jc.putClientProperty("WizardPanel_contentNumbered", Boolean.TRUE); } } @@ -81,10 +81,20 @@ final class AddImageWizardIterator implements WizardDescriptor.Iterator current() { @@ -98,17 +108,18 @@ final class AddImageWizardIterator implements WizardDescriptor.IteratorIngest is ongoing on another AddImageAction.ingestConfig.ongoingIngest.title=Ingest in progress AddImageTask.run.progress.adding=Adding\: {0} AddImageTask.interrupt.exception.msg=Error stopping add-image process. +AddImageWizardAddingProgressPanel.isValid.focusNext=Next > AddImageWizardAddingProgressPanel.stateStarted.progressBarText=*This process may take some time for large data sources. AddImageWizardAddingProgressVisual.addingDsComplete.text=Adding Data Source - Complete AddImageWizardAddingProgressVisual.getName.text=Add Data Source diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 7446ec1364..4fd28db906 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -88,6 +88,7 @@ AddImageAction.ingestConfig.ongoingIngest.msg=\u4ed6\u306e\u30c7\u30fc\u30 AddImageAction.ingestConfig.ongoingIngest.title=\u51e6\u7406\u4e2d AddImageTask.run.progress.adding=\u8ffd\u52a0\u4e2d\uff1a{0} AddImageTask.interrupt.exception.msg=\u30a4\u30e1\u30fc\u30b8\u8ffd\u52a0\u30d7\u30ed\u30bb\u30b9\u306e\u505c\u6b62\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 +AddImageWizardAddingProgressPanel.isValid.focusNext=\u6b21 > AddImageWizardAddingProgressPanel.stateStarted.progressBarText=*\u5927\u304d\u3044\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306e\u5834\u5408\u3001\u3053\u306e\u30d7\u30ed\u30bb\u30b9\u306f\u6642\u9593\u304c\u304b\u304b\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 AddImageWizardAddingProgressVisual.addingDsComplete.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0 - \u5b8c\u4e86 AddImageWizardAddingProgressVisual.getName.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0