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;
118 import org.
sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
157 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
160 mainFrame = WindowManager.getDefault().getMainWindow();
183 if (typeName != null) {
185 if (typeName.equalsIgnoreCase(c.toString())) {
209 "Case_caseType_singleUser=Single-user case",
210 "Case_caseType_multiUser=Multi-user case"
213 if (fromString(typeName) == SINGLE_USER_CASE) {
214 return Bundle.Case_caseType_singleUser();
216 return Bundle.Case_caseType_multiUser();
226 this.typeName = typeName;
241 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
393 .map(Events::toString)
394 .collect(Collectors.toSet()), listener);
405 .map(Events::toString)
406 .collect(Collectors.toSet()), listener);
429 eventTypes.forEach((
Events event) -> {
474 eventTypes.forEach((
Events event) -> {
488 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
489 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
490 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
542 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
543 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
547 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName());
549 if (caseDir.isEmpty()) {
550 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseDir());
569 "Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata.",
570 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
575 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
577 throw new CaseActionException(Bundle.Case_exceptionMessage_failedToReadMetadata(), ex);
580 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
591 return currentCase != null;
608 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"), ex);
631 if (openCase == null) {
632 throw new NoCurrentCaseException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
647 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
648 "Case.progressIndicatorTitle.closingCase=Closing Case"
652 if (null == currentCase) {
658 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
661 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
662 }
catch (CaseActionException ex) {
683 if (null == currentCase) {
704 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
705 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
706 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
707 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
711 if (null != currentCase) {
712 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
726 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
735 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
737 assert (null != dirLock);
740 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
744 progressIndicator.
finish();
759 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
763 if (null != currentCase) {
766 }
catch (CaseActionException ex) {
775 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
776 newCurrentCase.
open(isNewCase);
777 currentCase = newCurrentCase;
778 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
784 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
786 }
catch (CaseActionException ex) {
787 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
805 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
810 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
815 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
820 uniqueCaseName = uniqueCaseName.toLowerCase();
825 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
826 Date date =
new Date();
827 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
829 return uniqueCaseName;
842 File caseDirF =
new File(caseDir);
844 if (caseDirF.exists()) {
845 if (caseDirF.isFile()) {
846 throw new CaseActionException(
847 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
849 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
850 throw new CaseActionException(
851 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
856 boolean result = (caseDirF).mkdirs();
858 if (result ==
false) {
859 throw new CaseActionException(
860 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
864 String hostClause =
"";
869 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
870 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
871 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
872 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
874 if (result ==
false) {
875 throw new CaseActionException(
876 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
879 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
880 result =
new File(modulesOutDir).mkdir();
882 if (result ==
false) {
883 throw new CaseActionException(
884 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
888 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
889 result =
new File(reportsOutDir).mkdir();
891 if (result ==
false) {
892 throw new CaseActionException(
893 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
898 }
catch (MissingResourceException | CaseActionException e) {
899 throw new CaseActionException(
900 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
911 static Map<Long, String> getImagePaths(SleuthkitCase db) {
912 Map<Long, String> imgPaths =
new HashMap<>();
914 Map<Long, List<String>> imgPathsList = db.getImagePaths();
915 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
916 if (entry.getValue().size() > 0) {
917 imgPaths.put(entry.getKey(), entry.getValue().get(0));
920 }
catch (TskCoreException ex) {
921 logger.log(Level.SEVERE,
"Error getting image paths", ex);
943 "Case.progressMessage.deletingTextIndex=Deleting text index...",
944 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
945 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
946 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
949 boolean errorsOccurred =
false;
955 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
956 CaseDbConnectionInfo db;
958 Class.forName(
"org.postgresql.Driver");
959 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
960 Statement statement = connection.createStatement();) {
962 statement.execute(deleteCommand);
966 errorsOccurred =
true;
973 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
976 searchService.deleteTextIndex(metadata);
979 errorsOccurred =
true;
986 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
989 errorsOccurred =
true;
996 SwingUtilities.invokeLater(() -> {
997 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
1001 if (errorsOccurred) {
1002 throw new CaseActionException(Bundle.Case_exceptionMessage_errorsDeletingCase());
1016 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
1019 String resourcesNodeName = caseDir +
"_resources";
1022 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
1025 }
catch (InterruptedException ex) {
1028 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
1047 SwingUtilities.invokeLater(() -> {
1053 String backupDbPath = caseDb.getBackupDatabasePath();
1054 if (null != backupDbPath) {
1055 JOptionPane.showMessageDialog(
1057 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
1058 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
1059 JOptionPane.INFORMATION_MESSAGE);
1067 Map<Long, String> imgPaths = getImagePaths(caseDb);
1068 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
1069 long obj_id = entry.getKey();
1070 String path = entry.getValue();
1073 int response = JOptionPane.showConfirmDialog(
1075 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
1076 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
1077 JOptionPane.YES_NO_OPTION);
1078 if (response == JOptionPane.YES_OPTION) {
1079 MissingImageDialog.makeDialog(obj_id, caseDb);
1081 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1092 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1093 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1104 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1114 if (newCurrentCase.
hasData()) {
1133 SwingUtilities.invokeLater(() -> {
1143 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1145 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
false);
1146 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1171 File tempFolder =
new File(tempSubDirPath);
1172 if (tempFolder.isDirectory()) {
1173 File[] files = tempFolder.listFiles();
1174 if (files.length > 0) {
1175 for (File file : files) {
1176 if (file.isDirectory()) {
1219 return metadata.getCreatedDate();
1308 hostPath = Paths.get(caseDirectory);
1310 if (!hostPath.toFile().exists()) {
1311 hostPath.toFile().mkdirs();
1313 return hostPath.toString();
1396 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1398 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1412 List<Content> list = caseDb.getRootObjects();
1413 hasDataSources = (list.size() > 0);
1423 Set<TimeZone> timezones =
new HashSet<>();
1426 final Content dataSource = c.getDataSource();
1427 if ((dataSource != null) && (dataSource instanceof Image)) {
1428 Image image = (Image) dataSource;
1429 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1432 }
catch (TskCoreException ex) {
1433 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1455 if (!hasDataSources) {
1458 }
catch (TskCoreException ex) {
1459 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1554 logger.log(Level.WARNING,
"Unable to send notifcation regarding comment change due to no current case being open", ex);
1591 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1592 addReport(localPath, srcModuleName, reportName, null);
1609 public Report
addReport(String localPath, String srcModuleName, String reportName, Content parent)
throws TskCoreException {
1610 String normalizedLocalPath;
1612 if (localPath.toLowerCase().contains(
"http:")) {
1613 normalizedLocalPath = localPath;
1615 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1617 }
catch (InvalidPathException ex) {
1618 String errorMsg =
"Invalid local path provided: " + localPath;
1619 throw new TskCoreException(errorMsg, ex);
1621 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName, parent);
1635 return this.caseDb.getAllReports();
1646 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1647 for (Report report : reports) {
1648 this.caseDb.deleteReport(report);
1670 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata"
1672 void updateCaseDetails(CaseDetails caseDetails)
throws CaseActionException {
1675 metadata.setCaseDetails(caseDetails);
1676 }
catch (CaseMetadataException ex) {
1677 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex);
1679 if (!oldCaseDetails.getCaseNumber().equals(caseDetails.
getCaseNumber())) {
1680 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.
getCaseNumber()));
1682 if (!oldCaseDetails.getExaminerName().equals(caseDetails.
getExaminerName())) {
1683 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.
getExaminerName()));
1686 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.
getCaseDisplayName()));
1688 eventPublisher.
publish(
new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails));
1689 if (RuntimeProperties.runningWithGUI()) {
1690 SwingUtilities.invokeLater(() -> {
1693 RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.
getCaseDisplayName(), metadata.getFilePath().toString());
1694 }
catch (Exception ex) {
1695 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1723 metadata = caseMetaData;
1742 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1743 "Case.progressIndicatorTitle.openingCase=Opening Case",
1744 "Case.progressIndicatorCancelButton.label=Cancel",
1745 "Case.progressMessage.preparing=Preparing...",
1746 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1747 "Case.progressMessage.cancelling=Cancelling...",
1748 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1749 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1751 private void open(
boolean isNewCase)
throws CaseActionException {
1760 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1763 progressIndicatorTitle,
1764 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1765 Bundle.Case_progressIndicatorCancelButton_label(),
1766 cancelButtonListener);
1770 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1788 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1789 Future<Void> future = caseLockingExecutor.submit(() -> {
1791 open(isNewCase, progressIndicator);
1800 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1803 assert (null != resourcesLock);
1804 open(isNewCase, progressIndicator);
1805 }
catch (CaseActionException ex) {
1812 if (null != cancelButtonListener) {
1821 }
catch (InterruptedException discarded) {
1830 if (null != cancelButtonListener) {
1833 future.cancel(
true);
1836 }
catch (CancellationException discarded) {
1846 }
catch (ExecutionException ex) {
1855 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1857 progressIndicator.
finish();
1874 if (Thread.currentThread().isInterrupted()) {
1884 if (Thread.currentThread().isInterrupted()) {
1890 if (Thread.currentThread().isInterrupted()) {
1893 }
catch (CaseActionException ex) {
1902 }
catch (InterruptedException discarded) {
1904 close(progressIndicator);
1920 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1921 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1922 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1923 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1933 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1940 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1949 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1957 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1959 }
catch (TskCoreException ex) {
1960 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1962 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.databaseConnectionInfo.error.msg"), ex);
1964 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1979 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1980 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database.",
1981 "Case.unsupportedSchemaVersionMessage=Unsupported DB schema version - see log for details",
1982 "Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-User.",
1983 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. "
1984 +
"See Tools, Options, Multi-user."
1988 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1991 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1996 throw new CaseActionException(Case_databaseConnectionInfo_error_msg(), ex);
1999 throw new CaseActionException(Case_open_exception_multiUserCaseNotEnabled());
2001 }
catch (TskUnsupportedSchemaVersionException ex) {
2002 throw new CaseActionException(Bundle.Case_unsupportedSchemaVersionMessage(), ex);
2003 }
catch (TskCoreException ex) {
2004 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
2017 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
2018 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
2019 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
2020 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
2021 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
2027 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2029 if (Thread.currentThread().isInterrupted()) {
2036 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
2038 if (Thread.currentThread().isInterrupted()) {
2045 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
2046 this.caseServices =
new Services(caseDb);
2047 if (Thread.currentThread().isInterrupted()) {
2055 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
2057 if (Thread.currentThread().isInterrupted()) {
2066 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
2069 if (Thread.currentThread().isInterrupted()) {
2072 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
2079 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
2082 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
2083 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
2093 @NbBundle.Messages({
2094 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
2095 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
2096 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
2116 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
2119 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
2120 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
2121 Bundle.Case_progressIndicatorCancelButton_label(),
2122 cancelButtonListener);
2126 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2128 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2129 threadNameSuffix = threadNameSuffix.toLowerCase();
2131 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2132 Future<Void> future = executor.submit(() -> {
2133 service.openCaseResources(context);
2136 if (null != cancelButtonListener) {
2148 }
catch (InterruptedException discarded) {
2153 future.cancel(
true);
2154 }
catch (CancellationException discarded) {
2162 }
catch (ExecutionException ex) {
2169 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
2171 SwingUtilities.invokeLater(() -> {
2183 progressIndicator.
finish();
2186 if (Thread.currentThread().isInterrupted()) {
2195 private void close() throws CaseActionException {
2204 Bundle.Case_progressIndicatorTitle_closingCase());
2208 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2217 Future<Void> future = caseLockingExecutor.submit(() -> {
2219 close(progressIndicator);
2226 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2228 assert (null != resourcesLock);
2229 close(progressIndicator);
2243 }
catch (InterruptedException | CancellationException unused) {
2250 }
catch (ExecutionException ex) {
2251 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2254 progressIndicator.
finish();
2264 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2265 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2266 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2267 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2277 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2278 if (null != collaborationMonitor) {
2279 collaborationMonitor.shutdown();
2288 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2294 if (null != caseServices) {
2295 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2297 this.caseServices.
close();
2298 }
catch (IOException ex) {
2299 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2306 if (null != caseDb) {
2307 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2314 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2323 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2324 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2336 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2340 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2342 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2343 threadNameSuffix = threadNameSuffix.toLowerCase();
2345 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2346 Future<Void> future = executor.submit(() -> {
2347 service.closeCaseResources(context);
2352 }
catch (InterruptedException ex) {
2353 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2354 }
catch (CancellationException ex) {
2355 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2356 }
catch (ExecutionException ex) {
2357 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2360 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2361 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2365 progressIndicator.
finish();
2378 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2383 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
2386 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2401 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2414 if (!subDirectory.exists()) {
2415 subDirectory.mkdirs();
2417 return subDirectory.toString();
2508 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2537 return new Thread(task, threadName);
2574 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
throws CaseActionException {
2599 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner,
CaseType caseType)
throws CaseActionException {
2615 public static void open(String caseMetadataFilePath)
throws CaseActionException {
2672 return new File(filePath).isFile();
2711 return "ModuleOutput";
2724 public static PropertyChangeSupport
2726 return new PropertyChangeSupport(
Case.class
2758 public Image
addImage(String imgPath,
long imgId, String timeZone)
throws CaseActionException {
2760 Image newDataSource = caseDb.getImageById(imgId);
2762 return newDataSource;
2763 }
catch (TskCoreException ex) {
2764 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2791 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)
void notifyCentralRepoCommentChanged(long contentId, String newComment)
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)
String getConfigDirectory()
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 final String CONFIG_FOLDER
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()