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;
606 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"), ex);
619 if (openCase == null) {
620 throw new NoCurrentCaseException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
635 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
636 "Case.progressIndicatorTitle.closingCase=Closing Case"
640 if (null == currentCase) {
646 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
649 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
650 }
catch (CaseActionException ex) {
671 if (null == currentCase) {
692 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
693 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
694 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
695 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
699 if (null != currentCase) {
700 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
714 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
723 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
725 assert (null != dirLock);
728 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
732 progressIndicator.
finish();
747 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
751 if (null != currentCase) {
754 }
catch (CaseActionException ex) {
763 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
764 newCurrentCase.
open(isNewCase);
765 currentCase = newCurrentCase;
766 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
772 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
774 }
catch (CaseActionException ex) {
775 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
793 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
798 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
803 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
808 uniqueCaseName = uniqueCaseName.toLowerCase();
813 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
814 Date date =
new Date();
815 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
817 return uniqueCaseName;
830 File caseDirF =
new File(caseDir);
832 if (caseDirF.exists()) {
833 if (caseDirF.isFile()) {
834 throw new CaseActionException(
835 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
837 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
838 throw new CaseActionException(
839 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
844 boolean result = (caseDirF).mkdirs();
846 if (result ==
false) {
847 throw new CaseActionException(
848 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
852 String hostClause =
"";
857 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
858 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
859 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
860 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
862 if (result ==
false) {
863 throw new CaseActionException(
864 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
867 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
868 result =
new File(modulesOutDir).mkdir();
870 if (result ==
false) {
871 throw new CaseActionException(
872 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
876 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
877 result =
new File(reportsOutDir).mkdir();
879 if (result ==
false) {
880 throw new CaseActionException(
881 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
886 }
catch (MissingResourceException | CaseActionException e) {
887 throw new CaseActionException(
888 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
899 static Map<Long, String> getImagePaths(SleuthkitCase db) {
900 Map<Long, String> imgPaths =
new HashMap<>();
902 Map<Long, List<String>> imgPathsList = db.getImagePaths();
903 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
904 if (entry.getValue().size() > 0) {
905 imgPaths.put(entry.getKey(), entry.getValue().get(0));
908 }
catch (TskCoreException ex) {
909 logger.log(Level.SEVERE,
"Error getting image paths", ex);
931 "Case.progressMessage.deletingTextIndex=Deleting text index...",
932 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
933 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
934 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
937 boolean errorsOccurred =
false;
943 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
944 CaseDbConnectionInfo db;
946 Class.forName(
"org.postgresql.Driver");
947 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
948 Statement statement = connection.createStatement();) {
950 statement.execute(deleteCommand);
954 errorsOccurred =
true;
961 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
964 searchService.deleteTextIndex(metadata);
967 errorsOccurred =
true;
974 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
977 errorsOccurred =
true;
984 SwingUtilities.invokeLater(() -> {
985 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
989 if (errorsOccurred) {
990 throw new CaseActionException(Bundle.Case_exceptionMessage_errorsDeletingCase());
1004 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
1007 String resourcesNodeName = caseDir +
"_resources";
1010 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
1013 }
catch (InterruptedException ex) {
1016 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
1035 SwingUtilities.invokeLater(() -> {
1041 String backupDbPath = caseDb.getBackupDatabasePath();
1042 if (null != backupDbPath) {
1043 JOptionPane.showMessageDialog(
1045 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
1046 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
1047 JOptionPane.INFORMATION_MESSAGE);
1055 Map<Long, String> imgPaths = getImagePaths(caseDb);
1056 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
1057 long obj_id = entry.getKey();
1058 String path = entry.getValue();
1061 int response = JOptionPane.showConfirmDialog(
1063 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
1064 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
1065 JOptionPane.YES_NO_OPTION);
1066 if (response == JOptionPane.YES_OPTION) {
1067 MissingImageDialog.makeDialog(obj_id, caseDb);
1069 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1080 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1081 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1092 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1098 if (newCurrentCase.
hasData()) {
1117 SwingUtilities.invokeLater(() -> {
1127 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1129 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
false);
1130 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1155 File tempFolder =
new File(tempSubDirPath);
1156 if (tempFolder.isDirectory()) {
1157 File[] files = tempFolder.listFiles();
1158 if (files.length > 0) {
1159 for (File file : files) {
1160 if (file.isDirectory()) {
1203 return metadata.getCreatedDate();
1292 hostPath = Paths.get(caseDirectory);
1294 if (!hostPath.toFile().exists()) {
1295 hostPath.toFile().mkdirs();
1297 return hostPath.toString();
1370 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1372 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1386 List<Content> list = caseDb.getRootObjects();
1387 hasDataSources = (list.size() > 0);
1397 Set<TimeZone> timezones =
new HashSet<>();
1400 final Content dataSource = c.getDataSource();
1401 if ((dataSource != null) && (dataSource instanceof Image)) {
1402 Image image = (Image) dataSource;
1403 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1406 }
catch (TskCoreException ex) {
1407 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1429 if (!hasDataSources) {
1432 }
catch (TskCoreException ex) {
1433 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1549 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1550 addReport(localPath, srcModuleName, reportName, null);
1567 public Report
addReport(String localPath, String srcModuleName, String reportName, Content parent)
throws TskCoreException {
1568 String normalizedLocalPath;
1570 if (localPath.toLowerCase().contains(
"http:")) {
1571 normalizedLocalPath = localPath;
1573 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1575 }
catch (InvalidPathException ex) {
1576 String errorMsg =
"Invalid local path provided: " + localPath;
1577 throw new TskCoreException(errorMsg, ex);
1579 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName, parent);
1593 return this.caseDb.getAllReports();
1604 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1605 for (Report report : reports) {
1606 this.caseDb.deleteReport(report);
1628 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata"
1630 void updateCaseDetails(CaseDetails caseDetails)
throws CaseActionException {
1633 metadata.setCaseDetails(caseDetails);
1634 }
catch (CaseMetadataException ex) {
1635 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex);
1637 if (!oldCaseDetails.getCaseNumber().equals(caseDetails.
getCaseNumber())) {
1638 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.
getCaseNumber()));
1640 if (!oldCaseDetails.getExaminerName().equals(caseDetails.
getExaminerName())) {
1641 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.
getExaminerName()));
1644 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.
getCaseDisplayName()));
1646 eventPublisher.
publish(
new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails));
1647 if (RuntimeProperties.runningWithGUI()) {
1648 SwingUtilities.invokeLater(() -> {
1651 RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.
getCaseDisplayName(), metadata.getFilePath().toString());
1652 }
catch (Exception ex) {
1653 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1681 metadata = caseMetaData;
1700 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1701 "Case.progressIndicatorTitle.openingCase=Opening Case",
1702 "Case.progressIndicatorCancelButton.label=Cancel",
1703 "Case.progressMessage.preparing=Preparing...",
1704 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1705 "Case.progressMessage.cancelling=Cancelling...",
1706 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1707 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1709 private void open(
boolean isNewCase)
throws CaseActionException {
1718 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1721 progressIndicatorTitle,
1722 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1723 Bundle.Case_progressIndicatorCancelButton_label(),
1724 cancelButtonListener);
1728 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1746 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1747 Future<Void> future = caseLockingExecutor.submit(() -> {
1749 open(isNewCase, progressIndicator);
1758 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1761 assert (null != resourcesLock);
1762 open(isNewCase, progressIndicator);
1763 }
catch (CaseActionException ex) {
1770 if (null != cancelButtonListener) {
1779 }
catch (InterruptedException discarded) {
1788 if (null != cancelButtonListener) {
1791 future.cancel(
true);
1794 }
catch (CancellationException discarded) {
1804 }
catch (ExecutionException ex) {
1813 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1815 progressIndicator.
finish();
1832 if (Thread.currentThread().isInterrupted()) {
1842 if (Thread.currentThread().isInterrupted()) {
1848 if (Thread.currentThread().isInterrupted()) {
1851 }
catch (CaseActionException ex) {
1860 }
catch (InterruptedException discarded) {
1862 close(progressIndicator);
1878 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1879 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1880 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1881 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1891 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1898 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1907 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1915 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1917 }
catch (TskCoreException ex) {
1918 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1920 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.databaseConnectionInfo.error.msg"), ex);
1922 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1937 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1938 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database.",
1939 "Case.unsupportedSchemaVersionMessage=Unsupported DB schema version - see log for details",
1940 "Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-User.",
1941 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. "
1942 +
"See Tools, Options, Multi-user."
1946 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1949 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1954 throw new CaseActionException(Case_databaseConnectionInfo_error_msg(), ex);
1957 throw new CaseActionException(Case_open_exception_multiUserCaseNotEnabled());
1959 }
catch (TskUnsupportedSchemaVersionException ex) {
1960 throw new CaseActionException(Bundle.Case_unsupportedSchemaVersionMessage(), ex);
1961 }
catch (TskCoreException ex) {
1962 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
1975 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
1976 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
1977 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
1978 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
1979 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
1985 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
1987 if (Thread.currentThread().isInterrupted()) {
1994 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
1996 if (Thread.currentThread().isInterrupted()) {
2003 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
2004 this.caseServices =
new Services(caseDb);
2005 if (Thread.currentThread().isInterrupted()) {
2013 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
2015 if (Thread.currentThread().isInterrupted()) {
2024 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
2027 if (Thread.currentThread().isInterrupted()) {
2030 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
2037 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
2040 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
2041 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
2051 @NbBundle.Messages({
2052 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
2053 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
2054 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
2074 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
2077 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
2078 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
2079 Bundle.Case_progressIndicatorCancelButton_label(),
2080 cancelButtonListener);
2084 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2086 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2087 threadNameSuffix = threadNameSuffix.toLowerCase();
2089 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2090 Future<Void> future = executor.submit(() -> {
2091 service.openCaseResources(context);
2094 if (null != cancelButtonListener) {
2106 }
catch (InterruptedException discarded) {
2111 future.cancel(
true);
2112 }
catch (CancellationException discarded) {
2120 }
catch (ExecutionException ex) {
2127 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
2129 SwingUtilities.invokeLater(() -> {
2141 progressIndicator.
finish();
2144 if (Thread.currentThread().isInterrupted()) {
2153 private void close() throws CaseActionException {
2162 Bundle.Case_progressIndicatorTitle_closingCase());
2166 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2175 Future<Void> future = caseLockingExecutor.submit(() -> {
2177 close(progressIndicator);
2184 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2186 assert (null != resourcesLock);
2187 close(progressIndicator);
2201 }
catch (InterruptedException | CancellationException unused) {
2208 }
catch (ExecutionException ex) {
2209 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2212 progressIndicator.
finish();
2222 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2223 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2224 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2225 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2235 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2236 if (null != collaborationMonitor) {
2237 collaborationMonitor.shutdown();
2246 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2252 if (null != caseServices) {
2253 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2255 this.caseServices.
close();
2256 }
catch (IOException ex) {
2257 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2264 if (null != caseDb) {
2265 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2272 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2281 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2282 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2294 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2298 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2300 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2301 threadNameSuffix = threadNameSuffix.toLowerCase();
2303 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2304 Future<Void> future = executor.submit(() -> {
2305 service.closeCaseResources(context);
2310 }
catch (InterruptedException ex) {
2311 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2312 }
catch (CancellationException ex) {
2313 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2314 }
catch (ExecutionException ex) {
2315 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2318 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2319 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2323 progressIndicator.
finish();
2336 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2341 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
2344 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2359 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2372 if (!subDirectory.exists()) {
2373 subDirectory.mkdirs();
2375 return subDirectory.toString();
2466 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2495 return new Thread(task, threadName);
2532 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
throws CaseActionException {
2557 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner,
CaseType caseType)
throws CaseActionException {
2573 public static void open(String caseMetadataFilePath)
throws CaseActionException {
2630 return new File(filePath).isFile();
2669 return "ModuleOutput";
2682 public static PropertyChangeSupport
2684 return new PropertyChangeSupport(
Case.class
2716 public Image
addImage(String imgPath,
long imgId, String timeZone)
throws CaseActionException {
2718 Image newDataSource = caseDb.getImageById(imgId);
2720 return newDataSource;
2721 }
catch (TskCoreException ex) {
2722 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2749 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 Case getOpenCase()
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 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()