diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 8afd1f5cdb..4b6bbd2ac9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -152,6 +152,9 @@ CaseOpenAction.msgDlg.fileNotExist.title=Error CaseOpenAction.msgDlg.cantOpenCase.msg=Error\: could not open the case in folder {0}\: {1} CaseOpenAction.msgDlg.cantOpenCase.title=Error CaseCreateAction.msgDlg.cantCreateCase.msg=Cannot create case +IntervalErrorReport.NewIssues=new issue(s) +IntervalErrorReport.TotalIssues=total issue(s) +IntervalErrorReport.ErrorText=Database Connection Error CasePropertiesAction.window.title=Case Properties CasePropertiesForm.updateCaseName.msgDlg.empty.msg=The caseName cannot be empty. CasePropertiesForm.updateCaseName.msgDlg.empty.title=Error diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index e1a4fe6e9b..53cf8733b9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -75,7 +75,8 @@ public class Case { private static final String autopsyVer = Version.getVersion(); // current version of autopsy. Change it when the version is changed private static final String EVENT_CHANNEL_NAME = "%s-Case-Events"; private static String appName = null; - + private static IntervalErrorReportData tskErrorReporter = null; + /** * Name for the property that determines whether to show the dialog at * startup @@ -218,13 +219,6 @@ public class Case { this.services = new Services(db); } - /** - * Does initialization that would leak a reference to this if done in the - * constructor. - */ - private void init() { - } - /** * Gets the currently opened case, if there is one. * @@ -257,6 +251,8 @@ public class Case { * */ private static void changeCase(Case newCase) { + // force static initialization of error reporter + tskErrorReporter = IntervalErrorReportData.getInstance(); // close the existing case Case oldCase = Case.currentCase; Case.currentCase = null; @@ -373,8 +369,6 @@ public class Case { * constructor. */ Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType); - newCase.init(); - changeCase(newCase); } @@ -433,8 +427,6 @@ public class Case { * constructor. */ Case openedCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType); - openedCase.init(); - changeCase(openedCase); } catch (Exception ex) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IntervalErrorReportData.java b/Core/src/org/sleuthkit/autopsy/casemodule/IntervalErrorReportData.java new file mode 100644 index 0000000000..679917c476 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IntervalErrorReportData.java @@ -0,0 +1,103 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2015 Basis Technology Corp. + * Contact: carrier sleuthkit 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.casemodule; + +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * This class enables capturing errors and batching them for reporting on a + * no-more-than-x number of seconds basis. When created, you specify what type + * of error it will be batching, and the minimum time between user + * notifications. When the time between notifications has expired, the next + * error encountered will cause a report to be shown to the user. + */ +class IntervalErrorReportData implements SleuthkitCase.ErrorObserver { + + private static volatile IntervalErrorReportData instance; + private long newProblems; + private long totalProblems; + private long lastReportedDate; + private final int milliSecondsBetweenReports; + private final String message; + + /** + * Create a new IntervalErrorReprotData instance. + * + * @param secondsBetweenReports Minimum number of seconds between reports. + * It will not warn more frequently than this. + * @param message The message that will be shown when warning the user + */ + private IntervalErrorReportData(int secondsBetweenReports, String message) { + this.newProblems = 0; + this.totalProblems = 0; + this.lastReportedDate = 0; // arm the first warning by choosing zero + this.milliSecondsBetweenReports = secondsBetweenReports * 1000; // convert to milliseconds + this.message = message; + SleuthkitCase.addErrorObserver(this); + } + + /** + * Returns the singleton instance of this object + * + * @return the singleton instance of this object + */ + public static IntervalErrorReportData getInstance() { + if (instance == null) { + synchronized (IntervalErrorReportData.class) { + if (instance == null) { + instance = new IntervalErrorReportData(60, // No less than 60 seconds between warnings for errors + NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText")); + } + } + } + return instance; + } + + /** + * Call this to add problems to the class. When the time threshold is met + * (or if this is the first problem encountered), a warning will be shown to + * the user. + * + * @param newProblems the newProblems to set + * @param ex the exception for this error + */ + private void addProblems(long newProblems, Exception ex) { + this.newProblems += newProblems; + this.totalProblems += newProblems; + + long currentTimeStamp = System.currentTimeMillis(); + if ((currentTimeStamp - lastReportedDate) > milliSecondsBetweenReports) { + this.lastReportedDate = currentTimeStamp; + MessageNotifyUtil.Notify.error(message, ex.getMessage() + " " + + this.newProblems + " " + + NbBundle.getMessage(IntervalErrorReportData.class, "IntervalErrorReport.NewIssues") + + " " + this.totalProblems + " " + + NbBundle.getMessage(IntervalErrorReportData.class, "IntervalErrorReport.TotalIssues") + + "."); + this.newProblems = 0; + } + } + + @Override + public void receiveError(Exception ex) { + addProblems(1, ex); + } +}