disable Timeline and image gallery if there are more than 6M files in the DB

This commit is contained in:
millmanorama 2017-12-11 10:30:14 +01:00
parent 91c48b7e72
commit b68e794a0e
6 changed files with 201 additions and 80 deletions

View File

@ -0,0 +1,84 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.guiutils;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
/**
* Utilities for dealing with JavaFX gui components.
*
*/
public class JavaFXUtils {
private static final Logger logger = Logger.getLogger(JavaFXUtils.class.getName());
/**
* Image to use as title bar icon in dialogs
*/
private static final Image AUTOPSY_ICON;
static {
Image tempImg = null;
try {
tempImg = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NON-NLS
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS
}
AUTOPSY_ICON = tempImg;
}
private JavaFXUtils() {
}
/**
* Set the title bar icon for the given Dialog to be the Autopsy logo icon.
*
* @param dialog The dialog to set the title bar icon for.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
public static void setDialogIcons(Dialog<?> dialog) {
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().setAll(AUTOPSY_ICON);
}
@NbBundle.Messages(value = {"# {0} - Tool name",
"JavaFXUtils.showTooManyFiles.contentText="
+ "There are too many files in the DB to ensure reasonable performance."
+ " {0} will be disabled. ",
"JavaFXUtils.showTooManyFiles.headerText="})
public static void showTooManyFiles(String toolName) {
Alert dialog = new Alert(Alert.AlertType.INFORMATION, Bundle.JavaFXUtils_showTooManyFiles_contentText(toolName), ButtonType.OK);
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.setTitle(toolName);
setDialogIcons(dialog);
dialog.setHeaderText(Bundle.JavaFXUtils_showTooManyFiles_headerText());
dialog.showAndWait();
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2014-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.timeline;
import java.awt.Component;
import java.io.IOException;
import java.util.logging.Level;
import javafx.application.Platform;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import org.openide.awt.ActionID;
@ -36,8 +37,10 @@ import org.sleuthkit.autopsy.core.Installer;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.guiutils.JavaFXUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TskCoreException;
/**
* An Action that opens the Timeline window. Has methods to open the window in
@ -51,9 +54,8 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
public final class OpenTimelineAction extends CallableSystemAction implements Presenter.Toolbar {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(OpenTimelineAction.class.getName());
private static final boolean FX_INITED = Installer.isJavaFxInited();
private static final Logger logger = Logger.getLogger(OpenTimelineAction.class.getName());
private static final int FILE_LIMIT = 6_000_000;
private static TimeLineController timeLineController = null;
@ -78,15 +80,26 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr
/**
* We used to also check if Case.getCurrentCase().hasData() was true. We
* disabled that check because if it is executed while a data source is
* being added, it blocks the edt
* being added, it blocks the edt. We still do that in ImageGallery.
*/
return Case.isCaseOpen() && FX_INITED;
return Case.isCaseOpen() && Installer.isJavaFxInited();
}
@Override
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public void performAction() {
showTimeline();
if (tooManyFiles()) {
Platform.runLater(() ->
JavaFXUtils.showTooManyFiles(Bundle.Timeline_dialogs_title()));
synchronized (OpenTimelineAction.this) {
if (timeLineController != null) {
timeLineController.shutDownTimeLine();
}
}
setEnabled(false);
} else {
showTimeline();
}
}
@NbBundle.Messages({
@ -97,7 +110,7 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr
Case currentCase = Case.getCurrentCase();
if (currentCase.hasData() == false) {
MessageNotifyUtil.Message.info(Bundle.OpenTimeLineAction_msgdlg_text());
LOGGER.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
logger.log(Level.INFO, "Could not create timeline, there are no data sources.");// NON-NLS
return;
}
try {
@ -112,7 +125,7 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr
} catch (IOException iOException) {
MessageNotifyUtil.Message.error(Bundle.OpenTimelineAction_settingsErrorMessage());
LOGGER.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException);
logger.log(Level.SEVERE, "Failed to initialize per case timeline settings.", iOException);
}
} catch (IllegalStateException e) {
//there is no case... Do nothing.
@ -169,12 +182,12 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr
/**
* Set this action to be enabled/disabled
*
* @param value whether to enable this action or not
* @param enable whether to enable this action or not
*/
@Override
public void setEnabled(boolean value) {
super.setEnabled(value);
toolbarButton.setEnabled(value);
public void setEnabled(boolean enable) {
super.setEnabled(enable);
toolbarButton.setEnabled(enable);
}
/**
@ -189,4 +202,16 @@ public final class OpenTimelineAction extends CallableSystemAction implements Pr
toolbarButton.setText(this.getName());
return toolbarButton;
}
private boolean tooManyFiles() {
try {
return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1");
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, "Can not open timeline with no case open.", ex);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error counting files in the DB.", ex);
}
//if there is any doubt (no case, tskcore error, etc) just disable .
return false;
}
}

View File

@ -18,10 +18,7 @@
*/
package org.sleuthkit.autopsy.timeline;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import javafx.collections.FXCollections;
import javafx.scene.Node;
import javafx.scene.control.Alert;
@ -30,14 +27,13 @@ import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.controlsfx.dialog.ProgressDialog;
import org.controlsfx.tools.Borders;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.guiutils.JavaFXUtils;
/**
* Manager for the various prompts and dialogs Timeline shows the user related
@ -45,8 +41,6 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined;
*/
public final class PromptDialogManager {
private static final Logger LOGGER = Logger.getLogger(PromptDialogManager.class.getName());
@NbBundle.Messages("PrompDialogManager.buttonType.showTimeline=Continue")
private static final ButtonType CONTINUE = new ButtonType(Bundle.PrompDialogManager_buttonType_showTimeline(), ButtonBar.ButtonData.OK_DONE);
@ -56,21 +50,6 @@ public final class PromptDialogManager {
@NbBundle.Messages("PrompDialogManager.buttonType.update=Update DB")
private static final ButtonType UPDATE = new ButtonType(Bundle.PrompDialogManager_buttonType_update(), ButtonBar.ButtonData.OK_DONE);
/**
* Image to use as title bar icon in dialogs
*/
private static final Image AUTOPSY_ICON;
static {
Image tempImg = null;
try {
tempImg = new Image(new URL("nbresloc:/org/netbeans/core/startup/frame.gif").openStream()); //NON-NLS
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "Failed to load branded icon for progress dialog.", ex); //NON-NLS
}
AUTOPSY_ICON = tempImg;
}
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
private Dialog<?> currentDialog;
@ -143,8 +122,9 @@ public final class PromptDialogManager {
* @param dialog The dialog to set the title bar icon for.
*/
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
@Deprecated
public static void setDialogIcons(Dialog<?> dialog) {
((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().setAll(AUTOPSY_ICON);
JavaFXUtils.setDialogIcons(dialog);
}
/**
@ -168,6 +148,8 @@ public final class PromptDialogManager {
return currentDialog.showAndWait().map(CONTINUE::equals).orElse(false);
}
/**
* Prompt the user to confirm rebuilding the database for the given list of
* reasons.
@ -177,7 +159,8 @@ public final class PromptDialogManager {
* @return True if the user a confirms rebuilding the database.
*/
@NbBundle.Messages({
"PromptDialogManager.rebuildPrompt.headerText=The Timeline DB is incomplete and/or out of date. Some events may be missing or inaccurate and some features may be unavailable.",
"PromptDialogManager.rebuildPrompt.headerText=The Timeline DB is incomplete and/or out of date."
+ " Some events may be missing or inaccurate and some features may be unavailable.",
"PromptDialogManager.rebuildPrompt.details=Details"})
@ThreadConfined(type = ThreadConfined.ThreadType.JFX)
boolean confirmRebuild(List<String> rebuildReasons) {

View File

@ -58,6 +58,7 @@ import org.controlsfx.validation.Validator;
import org.joda.time.Interval;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.guiutils.JavaFXUtils;
import org.sleuthkit.autopsy.timeline.datamodel.SingleEvent;
import org.sleuthkit.autopsy.timeline.datamodel.eventtype.EventType;
import org.sleuthkit.autopsy.timeline.events.ViewInTimelineRequestedEvent;
@ -151,7 +152,7 @@ final class ShowInTimelineDialog extends Dialog<ViewInTimelineRequestedEvent> {
Validator.createPredicateValidator(NumberUtils::isDigits, Bundle.ShowInTimelineDialog_amountValidator_message()));
//configure dialog properties
PromptDialogManager.setDialogIcons(this);
JavaFXUtils.setDialogIcons(this);
initModality(Modality.APPLICATION_MODAL);
//add scenegraph loaded from fxml to this dialog.

View File

@ -48,7 +48,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.FileUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.timeline.PromptDialogManager;
import org.sleuthkit.autopsy.guiutils.JavaFXUtils;
import org.sleuthkit.autopsy.timeline.TimeLineController;
import org.sleuthkit.autopsy.timeline.snapshot.SnapShotReportWriter;
import org.sleuthkit.datamodel.TskCoreException;
@ -105,7 +105,7 @@ public class SaveSnapshotAsReport extends Action {
//prompt user to pick report name
TextInputDialog textInputDialog = new TextInputDialog();
PromptDialogManager.setDialogIcons(textInputDialog);
JavaFXUtils.setDialogIcons(textInputDialog);
textInputDialog.setTitle(Bundle.SaveSnapShotAsReport_action_dialogs_title());
textInputDialog.getEditor().setPromptText(Bundle.SaveSnapShotAsReport_reportName_prompt(defaultReportName));
textInputDialog.setHeaderText(Bundle.SaveSnapShotAsReport_reportName_header());

View File

@ -1,26 +1,28 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
* Autopsy Forensic Browser
*
* Copyright 2015-17 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.imagegallery.actions;
import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import javafx.application.Platform;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
@ -29,6 +31,7 @@ import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionRegistration;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction;
import org.openide.util.actions.Presenter;
@ -37,49 +40,53 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.Installer;
import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.guiutils.JavaFXUtils;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
import org.sleuthkit.datamodel.TskCoreException;
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.imagegallery.OpenAction")
@ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 101),
@ActionReference(path = "Toolbars/Case", position = 101)
})
@ActionReference(path = "Toolbars/Case", position = 101)})
@ActionRegistration(displayName = "#CTL_OpenAction", lazy = false)
@Messages({"CTL_OpenAction=View Images/Videos",
"OpenAction.stale.confDlg.msg=The image / video database may be out of date. " +
"Do you want to update and listen for further ingest results?\n" +
"Choosing 'yes' will update the database and enable listening to future ingests.",
"OpenAction.stale.confDlg.msg=The image / video database may be out of date. "
+ "Do you want to update and listen for further ingest results?\n"
+ "Choosing 'yes' will update the database and enable listening to future ingests.",
"OpenAction.stale.confDlg.title=Image Gallery"})
public final class OpenAction extends CallableSystemAction implements Presenter.Toolbar {
private static final Logger LOGGER = Logger.getLogger(OpenAction.class.getName());
private static final Logger logger = Logger.getLogger(OpenAction.class.getName());
private static final String VIEW_IMAGES_VIDEOS = Bundle.CTL_OpenAction();
private final JButton toolbarButton = new JButton();
private final PropertyChangeListener pcl;
private static final long FILE_LIMIT = 6_000_000;
public OpenAction() {
super();
toolbarButton.addActionListener(actionEvent -> performAction());
pcl = (PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) {
setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null);
setEnabled(RuntimeProperties.runningWithGUI() && evt.getNewValue() != null);
}
};
Case.addPropertyChangeListener(pcl);
this.setEnabled(false);
}
@Override
public boolean isEnabled() {
return Case.isCaseOpen() && Installer.isJavaFxInited() && Case.getCurrentCase().hasData();
}
/** Returns the toolbar component of this action
/**
* Returns the toolbar component of this action
*
* @return component the toolbar button */
* @return component the toolbar button
*/
@Override
public Component getToolbarPresenter() {
ImageIcon icon = new ImageIcon(getClass().getResource("btn_icon_image_gallery_26.png")); //NON-NLS
@ -87,7 +94,7 @@ public final class OpenAction extends CallableSystemAction implements Presenter.
toolbarButton.setText(this.getName());
return toolbarButton;
}
/**
* Set this action to be enabled/disabled
*
@ -98,26 +105,35 @@ public final class OpenAction extends CallableSystemAction implements Presenter.
super.setEnabled(value);
toolbarButton.setEnabled(value);
}
@Override
@SuppressWarnings("fallthrough")
@NbBundle.Messages({
"OpenAction.dialogTitle=Image Gallery"
})
public void performAction() {
//check case
if (!Case.isCaseOpen()) {
return;
}
final Case currentCase = Case.getCurrentCase();
if (tooManyFiles()) {
Platform.runLater(() ->
JavaFXUtils.showTooManyFiles(Bundle.OpenAction_dialogTitle()));
setEnabled(false);
return;
}
if (ImageGalleryModule.isDrawableDBStale(currentCase)) {
//drawable db is stale, ask what to do
int answer = JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(), Bundle.OpenAction_stale_confDlg_msg(),
Bundle.OpenAction_stale_confDlg_title(), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
switch (answer) {
case JOptionPane.YES_OPTION:
ImageGalleryController.getDefault().setListeningEnabled(true);
//fall through
//fall through
case JOptionPane.NO_OPTION:
ImageGalleryTopComponent.openTopComponent();
break;
@ -129,17 +145,29 @@ public final class OpenAction extends CallableSystemAction implements Presenter.
ImageGalleryTopComponent.openTopComponent();
}
}
private boolean tooManyFiles() {
try {
return FILE_LIMIT < Case.getCurrentCase().getSleuthkitCase().countFilesWhere("1 = 1");
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, "Can not open image gallery with no case open.", ex);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error counting files in the DB.", ex);
}
//if there is any doubt (no case, tskcore error, etc) just disable .
return false;
}
@Override
public String getName() {
return VIEW_IMAGES_VIDEOS;
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
@Override
public boolean asynchronous() {
return false; // run on edt