19 package org.sleuthkit.autopsy.casemodule;
21 import java.awt.Frame;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.beans.PropertyChangeListener;
25 import java.beans.PropertyChangeSupport;
27 import java.io.IOException;
28 import java.nio.file.InvalidPathException;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.sql.Connection;
32 import java.sql.DriverManager;
33 import java.sql.SQLException;
34 import java.sql.Statement;
35 import java.text.SimpleDateFormat;
36 import java.util.Collection;
37 import java.util.Date;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
42 import java.util.MissingResourceException;
44 import java.util.TimeZone;
45 import java.util.UUID;
46 import java.util.concurrent.CancellationException;
47 import java.util.concurrent.ExecutionException;
48 import java.util.concurrent.ExecutorService;
49 import java.util.concurrent.Executors;
50 import java.util.concurrent.Future;
51 import java.util.concurrent.ThreadFactory;
52 import java.util.concurrent.TimeUnit;
53 import java.util.logging.Level;
54 import java.util.stream.Collectors;
55 import java.util.stream.Stream;
56 import javax.annotation.concurrent.GuardedBy;
57 import javax.annotation.concurrent.ThreadSafe;
58 import javax.swing.JOptionPane;
59 import javax.swing.SwingUtilities;
60 import org.openide.util.Lookup;
61 import org.openide.util.NbBundle;
62 import org.openide.util.NbBundle.Messages;
63 import org.openide.util.actions.CallableSystemAction;
64 import org.openide.windows.WindowManager;
117 import org.
sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
155 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
158 mainFrame = WindowManager.getDefault().getMainWindow();
181 if (typeName != null) {
183 if (typeName.equalsIgnoreCase(c.toString())) {
207 "Case_caseType_singleUser=Single-user case",
208 "Case_caseType_multiUser=Multi-user case"
211 if (fromString(typeName) == SINGLE_USER_CASE) {
212 return Bundle.Case_caseType_singleUser();
214 return Bundle.Case_caseType_multiUser();
224 this.typeName = typeName;
239 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
385 .map(Events::toString)
386 .collect(Collectors.toSet()), listener);
397 .map(Events::toString)
398 .collect(Collectors.toSet()), listener);
421 eventTypes.forEach((
Events event) -> {
466 eventTypes.forEach((
Events event) -> {
480 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
481 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
482 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
534 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
535 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
539 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName());
541 if (caseDir.isEmpty()) {
542 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseDir());
561 "Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata.",
562 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
567 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
569 throw new CaseActionException(Bundle.Case_exceptionMessage_failedToReadMetadata(), ex);
572 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
583 return currentCase != null;
600 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"), ex);
623 if (openCase == null) {
624 throw new NoCurrentCaseException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
639 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
640 "Case.progressIndicatorTitle.closingCase=Closing Case"
644 if (null == currentCase) {
650 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
653 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
654 }
catch (CaseActionException ex) {
675 if (null == currentCase) {
696 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
697 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
698 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
699 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
703 if (null != currentCase) {
704 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
718 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
727 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
729 assert (null != dirLock);
732 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
736 progressIndicator.
finish();
751 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
755 if (null != currentCase) {
758 }
catch (CaseActionException ex) {
767 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
768 newCurrentCase.
open(isNewCase);
769 currentCase = newCurrentCase;
770 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
776 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
778 }
catch (CaseActionException ex) {
779 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
797 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
802 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
807 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
812 uniqueCaseName = uniqueCaseName.toLowerCase();
817 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
818 Date date =
new Date();
819 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
821 return uniqueCaseName;
834 File caseDirF =
new File(caseDir);
836 if (caseDirF.exists()) {
837 if (caseDirF.isFile()) {
838 throw new CaseActionException(
839 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
841 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
842 throw new CaseActionException(
843 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
848 boolean result = (caseDirF).mkdirs();
850 if (result ==
false) {
851 throw new CaseActionException(
852 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
856 String hostClause =
"";
861 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
862 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
863 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
864 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
866 if (result ==
false) {
867 throw new CaseActionException(
868 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
871 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
872 result =
new File(modulesOutDir).mkdir();
874 if (result ==
false) {
875 throw new CaseActionException(
876 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
880 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
881 result =
new File(reportsOutDir).mkdir();
883 if (result ==
false) {
884 throw new CaseActionException(
885 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
890 }
catch (MissingResourceException | CaseActionException e) {
891 throw new CaseActionException(
892 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
903 static Map<Long, String> getImagePaths(SleuthkitCase db) {
904 Map<Long, String> imgPaths =
new HashMap<>();
906 Map<Long, List<String>> imgPathsList = db.getImagePaths();
907 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
908 if (entry.getValue().size() > 0) {
909 imgPaths.put(entry.getKey(), entry.getValue().get(0));
912 }
catch (TskCoreException ex) {
913 logger.log(Level.SEVERE,
"Error getting image paths", ex);
935 "Case.progressMessage.deletingTextIndex=Deleting text index...",
936 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
937 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
938 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
941 boolean errorsOccurred =
false;
947 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
948 CaseDbConnectionInfo db;
950 Class.forName(
"org.postgresql.Driver");
951 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
952 Statement statement = connection.createStatement();) {
954 statement.execute(deleteCommand);
958 errorsOccurred =
true;
965 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
968 searchService.deleteTextIndex(metadata);
971 errorsOccurred =
true;
978 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
981 errorsOccurred =
true;
988 SwingUtilities.invokeLater(() -> {
989 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
993 if (errorsOccurred) {
994 throw new CaseActionException(Bundle.Case_exceptionMessage_errorsDeletingCase());
1008 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
1011 String resourcesNodeName = caseDir +
"_resources";
1014 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
1017 }
catch (InterruptedException ex) {
1020 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
1039 SwingUtilities.invokeLater(() -> {
1045 String backupDbPath = caseDb.getBackupDatabasePath();
1046 if (null != backupDbPath) {
1047 JOptionPane.showMessageDialog(
1049 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
1050 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
1051 JOptionPane.INFORMATION_MESSAGE);
1059 Map<Long, String> imgPaths = getImagePaths(caseDb);
1060 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
1061 long obj_id = entry.getKey();
1062 String path = entry.getValue();
1065 int response = JOptionPane.showConfirmDialog(
1067 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
1068 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
1069 JOptionPane.YES_NO_OPTION);
1070 if (response == JOptionPane.YES_OPTION) {
1071 MissingImageDialog.makeDialog(obj_id, caseDb);
1073 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1084 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1085 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1096 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1102 if (newCurrentCase.
hasData()) {
1121 SwingUtilities.invokeLater(() -> {
1131 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1133 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
false);
1134 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1159 File tempFolder =
new File(tempSubDirPath);
1160 if (tempFolder.isDirectory()) {
1161 File[] files = tempFolder.listFiles();
1162 if (files.length > 0) {
1163 for (File file : files) {
1164 if (file.isDirectory()) {
1207 return metadata.getCreatedDate();
1296 hostPath = Paths.get(caseDirectory);
1298 if (!hostPath.toFile().exists()) {
1299 hostPath.toFile().mkdirs();
1301 return hostPath.toString();
1374 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1376 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1390 List<Content> list = caseDb.getRootObjects();
1391 hasDataSources = (list.size() > 0);
1401 Set<TimeZone> timezones =
new HashSet<>();
1404 final Content dataSource = c.getDataSource();
1405 if ((dataSource != null) && (dataSource instanceof Image)) {
1406 Image image = (Image) dataSource;
1407 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1410 }
catch (TskCoreException ex) {
1411 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1433 if (!hasDataSources) {
1436 }
catch (TskCoreException ex) {
1437 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1553 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1554 addReport(localPath, srcModuleName, reportName, null);
1571 public Report
addReport(String localPath, String srcModuleName, String reportName, Content parent)
throws TskCoreException {
1572 String normalizedLocalPath;
1574 if (localPath.toLowerCase().contains(
"http:")) {
1575 normalizedLocalPath = localPath;
1577 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1579 }
catch (InvalidPathException ex) {
1580 String errorMsg =
"Invalid local path provided: " + localPath;
1581 throw new TskCoreException(errorMsg, ex);
1583 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName, parent);
1597 return this.caseDb.getAllReports();
1608 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1609 for (Report report : reports) {
1610 this.caseDb.deleteReport(report);
1632 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata"
1634 void updateCaseDetails(CaseDetails caseDetails)
throws CaseActionException {
1637 metadata.setCaseDetails(caseDetails);
1638 }
catch (CaseMetadataException ex) {
1639 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex);
1641 if (!oldCaseDetails.getCaseNumber().equals(caseDetails.
getCaseNumber())) {
1642 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.
getCaseNumber()));
1644 if (!oldCaseDetails.getExaminerName().equals(caseDetails.
getExaminerName())) {
1645 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.
getExaminerName()));
1648 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.
getCaseDisplayName()));
1650 eventPublisher.
publish(
new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails));
1651 if (RuntimeProperties.runningWithGUI()) {
1652 SwingUtilities.invokeLater(() -> {
1655 RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.
getCaseDisplayName(), metadata.getFilePath().toString());
1656 }
catch (Exception ex) {
1657 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1685 metadata = caseMetaData;
1704 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1705 "Case.progressIndicatorTitle.openingCase=Opening Case",
1706 "Case.progressIndicatorCancelButton.label=Cancel",
1707 "Case.progressMessage.preparing=Preparing...",
1708 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1709 "Case.progressMessage.cancelling=Cancelling...",
1710 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1711 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1713 private void open(
boolean isNewCase)
throws CaseActionException {
1722 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1725 progressIndicatorTitle,
1726 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1727 Bundle.Case_progressIndicatorCancelButton_label(),
1728 cancelButtonListener);
1732 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1750 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1751 Future<Void> future = caseLockingExecutor.submit(() -> {
1753 open(isNewCase, progressIndicator);
1762 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1765 assert (null != resourcesLock);
1766 open(isNewCase, progressIndicator);
1767 }
catch (CaseActionException ex) {
1774 if (null != cancelButtonListener) {
1783 }
catch (InterruptedException discarded) {
1792 if (null != cancelButtonListener) {
1795 future.cancel(
true);
1798 }
catch (CancellationException discarded) {
1808 }
catch (ExecutionException ex) {
1817 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1819 progressIndicator.
finish();
1836 if (Thread.currentThread().isInterrupted()) {
1846 if (Thread.currentThread().isInterrupted()) {
1852 if (Thread.currentThread().isInterrupted()) {
1855 }
catch (CaseActionException ex) {
1864 }
catch (InterruptedException discarded) {
1866 close(progressIndicator);
1882 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1883 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1884 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1885 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1895 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1902 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1911 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1919 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1921 }
catch (TskCoreException ex) {
1922 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1924 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.databaseConnectionInfo.error.msg"), ex);
1926 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1941 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1942 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database.",
1943 "Case.unsupportedSchemaVersionMessage=Unsupported DB schema version - see log for details",
1944 "Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-User.",
1945 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. "
1946 +
"See Tools, Options, Multi-user."
1950 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1953 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1958 throw new CaseActionException(Case_databaseConnectionInfo_error_msg(), ex);
1961 throw new CaseActionException(Case_open_exception_multiUserCaseNotEnabled());
1963 }
catch (TskUnsupportedSchemaVersionException ex) {
1964 throw new CaseActionException(Bundle.Case_unsupportedSchemaVersionMessage(), ex);
1965 }
catch (TskCoreException ex) {
1966 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
1979 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
1980 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
1981 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
1982 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
1983 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
1989 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
1991 if (Thread.currentThread().isInterrupted()) {
1998 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
2000 if (Thread.currentThread().isInterrupted()) {
2007 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
2008 this.caseServices =
new Services(caseDb);
2009 if (Thread.currentThread().isInterrupted()) {
2017 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
2019 if (Thread.currentThread().isInterrupted()) {
2028 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
2031 if (Thread.currentThread().isInterrupted()) {
2034 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
2041 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
2044 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
2045 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
2055 @NbBundle.Messages({
2056 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
2057 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
2058 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
2078 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
2081 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
2082 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
2083 Bundle.Case_progressIndicatorCancelButton_label(),
2084 cancelButtonListener);
2088 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2090 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2091 threadNameSuffix = threadNameSuffix.toLowerCase();
2093 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2094 Future<Void> future = executor.submit(() -> {
2095 service.openCaseResources(context);
2098 if (null != cancelButtonListener) {
2110 }
catch (InterruptedException discarded) {
2115 future.cancel(
true);
2116 }
catch (CancellationException discarded) {
2124 }
catch (ExecutionException ex) {
2131 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
2133 SwingUtilities.invokeLater(() -> {
2145 progressIndicator.
finish();
2148 if (Thread.currentThread().isInterrupted()) {
2157 private void close() throws CaseActionException {
2166 Bundle.Case_progressIndicatorTitle_closingCase());
2170 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2179 Future<Void> future = caseLockingExecutor.submit(() -> {
2181 close(progressIndicator);
2188 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2190 assert (null != resourcesLock);
2191 close(progressIndicator);
2205 }
catch (InterruptedException | CancellationException unused) {
2212 }
catch (ExecutionException ex) {
2213 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2216 progressIndicator.
finish();
2226 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2227 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2228 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2229 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2239 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2240 if (null != collaborationMonitor) {
2241 collaborationMonitor.shutdown();
2250 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2256 if (null != caseServices) {
2257 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2259 this.caseServices.
close();
2260 }
catch (IOException ex) {
2261 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2268 if (null != caseDb) {
2269 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2276 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2285 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2286 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2298 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2302 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2304 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2305 threadNameSuffix = threadNameSuffix.toLowerCase();
2307 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2308 Future<Void> future = executor.submit(() -> {
2309 service.closeCaseResources(context);
2314 }
catch (InterruptedException ex) {
2315 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2316 }
catch (CancellationException ex) {
2317 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2318 }
catch (ExecutionException ex) {
2319 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2322 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2323 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2327 progressIndicator.
finish();
2340 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2345 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
2348 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2363 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2376 if (!subDirectory.exists()) {
2377 subDirectory.mkdirs();
2379 return subDirectory.toString();
2470 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2499 return new Thread(task, threadName);
2536 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
throws CaseActionException {
2561 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner,
CaseType caseType)
throws CaseActionException {
2577 public static void open(String caseMetadataFilePath)
throws CaseActionException {
2634 return new File(filePath).isFile();
2673 return "ModuleOutput";
2686 public static PropertyChangeSupport
2688 return new PropertyChangeSupport(
Case.class
2720 public Image
addImage(String imgPath,
long imgId, String timeZone)
throws CaseActionException {
2722 Image newDataSource = caseDb.getImageById(imgId);
2724 return newDataSource;
2725 }
catch (TskCoreException ex) {
2726 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2753 public void deleteReports(Collection<? extends Report> reports,
boolean deleteFromDisk)
throws TskCoreException {
String getLogDirectoryPath()
static final AutopsyEventPublisher eventPublisher
List< Content > getDataSources()
String getModuleOutputDirectoryRelativePath()
void notifyContentTagDeleted(ContentTag deletedTag)
Case(CaseMetadata caseMetaData)
static CaseType fromString(String typeName)
static final String CASE_ACTION_THREAD_NAME
void publishLocally(AutopsyEvent event)
static void createAsCurrentCase(CaseType caseType, String caseDir, CaseDetails caseDetails)
void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag)
String getExaminerPhone()
Set< TimeZone > getTimeZones()
static String getNameForTitle()
Image addImage(String imgPath, long imgId, String timeZone)
static synchronized IngestManager getInstance()
static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir)
static boolean runningWithGUI
static void closeCurrentCase()
String getTempDirectory()
static boolean existsCurrentCase()
static void removePropertyChangeListener(PropertyChangeListener listener)
void start(String message, int totalWorkUnits)
static final Logger logger
void publish(AutopsyEvent event)
static final int RESOURCES_LOCK_TIMOUT_HOURS
String getLocalizedDisplayName()
ADDING_DATA_SOURCE_FAILED
static final String EXPORT_FOLDER
String getCaseDirectory()
static String getAppName()
void notifyTagDefinitionChanged(String changedTagName)
static volatile Frame mainFrame
static String convertTimeZone(String timeZoneId)
static boolean driveExists(String path)
static void openCoreWindows()
void addSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
synchronized static void setLogDirectory(String directoryPath)
TaskThreadFactory(String threadName)
static final String CACHE_FOLDER
static String getAutopsyVersion()
CaseType(String typeName)
Case(CaseType caseType, String caseDir, CaseDetails caseDetails)
String getReportDirectory()
void createCaseData(ProgressIndicator progressIndicator)
static boolean getIsMultiUserModeEnabled()
void addReport(String localPath, String srcModuleName, String reportName)
static void updateGUIForCaseOpened(Case newCurrentCase)
static CaseDbConnectionInfo getDatabaseConnectionInfo()
String getModulesOutputDirAbsPath()
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
void closeAppServiceCaseResources()
static final String SINGLE_USER_CASE_DB_NAME
static void deleteCase(CaseMetadata metadata)
void deleteReports(Collection<?extends Report > reports, boolean deleteFromDisk)
synchronized void closeRemoteEventChannel()
volatile ExecutorService caseLockingExecutor
List< Report > getAllReports()
static void clearTempSubDir(String tempSubDirPath)
static boolean isValidName(String caseName)
void acquireSharedCaseDirLock(String caseDir)
CollaborationMonitor collaborationMonitor
void releaseSharedCaseDirLock(String caseDir)
static void shutDownTaskExecutor(ExecutorService executor)
static void closeCoreWindows()
ProgressIndicator getProgressIndicator()
static String getModulesOutputDirRelPath()
Set< TimeZone > getTimeZone()
void openCaseData(ProgressIndicator progressIndicator)
static final String MODULE_FOLDER
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
synchronized void openRemoteEventChannel(String channelName)
String getCaseDisplayName()
void openAppServiceCaseResources()
void openServices(ProgressIndicator progressIndicator)
static void invokeStartupDialog()
static String displayNameToUniqueName(String caseDisplayName)
void open(boolean isNewCase)
static void openAsCurrentCase(String caseMetadataFilePath)
static void removeEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static final int DIR_LOCK_TIMOUT_HOURS
void close(ProgressIndicator progressIndicator)
SleuthkitCase getSleuthkitCase()
void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag)
static PropertyChangeSupport getPropertyChangeSupport()
String getCacheDirectory()
static void addPropertyChangeListener(PropertyChangeListener listener)
void removeSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
String getModuleDirectory()
Thread newThread(Runnable task)
static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber)
final CaseMetadata metadata
void deleteReports(Collection<?extends Report > reports)
void notifyDataSourceAdded(Content dataSource, UUID addingDataSourceEventId)
Report addReport(String localPath, String srcModuleName, String reportName, Content parent)
static boolean pathExists(String filePath)
BLACKBOARD_ARTIFACT_TAG_ADDED
static void open(String caseMetadataFilePath)
static void openAsCurrentCase(Case newCurrentCase, boolean isNewCase)
String getOutputDirectory()
static void error(String title, String message)
String getOrCreateSubdirectory(String subDirectoryName)
boolean equalsName(String otherTypeName)
static final String EVENT_CHANNEL_NAME
static Case getCurrentCase()
static String getLocalHostName()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static String convertToAlphaNumericFormat(String timeZoneId)
static final String LOG_FOLDER
Lock tryGetSharedLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static String getAppName()
static synchronized CoordinationService getInstance()
static volatile Case currentCase
static String getVersion()
String getExportDirectory()
static void updateGUIForCaseClosed()
void notifyAddingDataSource(UUID eventId)
CoordinationService.Lock caseDirLock
static void addEventSubscriber(String eventName, PropertyChangeListener subscriber)
void notifyContentTagAdded(ContentTag newTag)
void cancelAllIngestJobs(IngestJob.CancellationReason reason)
static final String CASE_RESOURCES_THREAD_NAME
static StartupWindowProvider getInstance()
static void deleteCurrentCase()
static boolean deleteDir(File dirPath)
static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
void notifyFailedAddingDataSource(UUID addingDataSourceEventId)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
static final Object caseActionSerializationLock
void open(boolean isNewCase, ProgressIndicator progressIndicator)
static boolean isCaseOpen()
String getTextIndexName()
static final String REPORTS_FOLDER
void progress(String message)
static void createCaseDirectory(String caseDir, CaseType caseType)
static final String TEMP_FOLDER
BLACKBOARD_ARTIFACT_TAG_DELETED
static void addEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator)
static void error(String message)
String getExaminerEmail()