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;
114 import org.
sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
153 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
156 mainFrame = WindowManager.getDefault().getMainWindow();
179 if (typeName != null) {
181 if (typeName.equalsIgnoreCase(c.toString())) {
205 "Case_caseType_singleUser=Single-user case",
206 "Case_caseType_multiUser=Multi-user case"
209 if (fromString(typeName) == SINGLE_USER_CASE) {
210 return Bundle.Case_caseType_singleUser();
212 return Bundle.Case_caseType_multiUser();
222 this.typeName = typeName;
237 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
360 .map(Events::toString)
361 .collect(Collectors.toSet()), listener);
372 .map(Events::toString)
373 .collect(Collectors.toSet()), listener);
396 eventTypes.forEach((
Events event) -> {
441 eventTypes.forEach((
Events event) -> {
455 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
456 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
457 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
482 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
483 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
486 if (caseDisplayName.isEmpty()) {
489 if (caseDir.isEmpty()) {
509 "Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata.",
510 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
515 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
520 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
531 return currentCase != null;
549 if (null != currentCase) {
552 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
565 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
566 "Case.progressIndicatorTitle.closingCase=Closing Case"
570 if (null == currentCase) {
576 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
579 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
601 if (null == currentCase) {
622 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
623 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
624 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
625 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
629 if (null != currentCase) {
644 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
653 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
655 assert (null != dirLock);
658 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
662 progressIndicator.
finish();
677 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
681 if (null != currentCase) {
693 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
694 newCurrentCase.
open(isNewCase);
695 currentCase = newCurrentCase;
696 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
702 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
705 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
723 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
728 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
733 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
738 uniqueCaseName = uniqueCaseName.toLowerCase();
743 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
744 Date date =
new Date();
745 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
747 return uniqueCaseName;
760 File caseDirF =
new File(caseDir);
762 if (caseDirF.exists()) {
763 if (caseDirF.isFile()) {
765 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
767 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
768 throw new CaseActionException(
769 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
774 boolean result = (caseDirF).mkdirs();
776 if (result ==
false) {
777 throw new CaseActionException(
778 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
782 String hostClause =
"";
785 hostClause = File.separator + NetworkUtils.getLocalHostName();
787 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
788 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
789 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
790 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
792 if (result ==
false) {
793 throw new CaseActionException(
794 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
797 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
798 result =
new File(modulesOutDir).mkdir();
800 if (result ==
false) {
801 throw new CaseActionException(
802 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
806 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
807 result =
new File(reportsOutDir).mkdir();
809 if (result ==
false) {
810 throw new CaseActionException(
811 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
816 }
catch (MissingResourceException | CaseActionException e) {
817 throw new CaseActionException(
818 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
829 static Map<Long, String> getImagePaths(SleuthkitCase db) {
830 Map<Long, String> imgPaths =
new HashMap<>();
832 Map<Long, List<String>> imgPathsList = db.getImagePaths();
833 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
834 if (entry.getValue().size() > 0) {
835 imgPaths.put(entry.getKey(), entry.getValue().get(0));
838 }
catch (TskCoreException ex) {
839 logger.log(Level.SEVERE,
"Error getting image paths", ex);
861 "Case.progressMessage.deletingTextIndex=Deleting text index...",
862 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
863 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
864 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
867 boolean errorsOccurred =
false;
873 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
874 CaseDbConnectionInfo db;
876 Class.forName(
"org.postgresql.Driver");
877 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
878 Statement statement = connection.createStatement();) {
880 statement.execute(deleteCommand);
884 errorsOccurred =
true;
891 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
894 searchService.deleteTextIndex(metadata);
897 errorsOccurred =
true;
904 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
907 errorsOccurred =
true;
914 SwingUtilities.invokeLater(() -> {
915 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
919 if (errorsOccurred) {
934 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
937 String resourcesNodeName = caseDir +
"_resources";
940 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
943 }
catch (InterruptedException ex) {
946 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
955 SwingUtilities.invokeLater(() -> {
961 String backupDbPath = caseDb.getBackupDatabasePath();
962 if (null != backupDbPath) {
963 JOptionPane.showMessageDialog(
965 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
966 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
967 JOptionPane.INFORMATION_MESSAGE);
975 Map<Long, String> imgPaths = getImagePaths(caseDb);
976 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
977 long obj_id = entry.getKey();
978 String path = entry.getValue();
981 int response = JOptionPane.showConfirmDialog(
983 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
984 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
985 JOptionPane.YES_NO_OPTION);
986 if (response == JOptionPane.YES_OPTION) {
987 MissingImageDialog.makeDialog(obj_id, caseDb);
989 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1000 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1001 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1010 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1016 if (newCurrentCase.
hasData()) {
1035 SwingUtilities.invokeLater(() -> {
1045 CallableSystemAction
1047 ).setEnabled(
false);
1048 CallableSystemAction
1050 ).setEnabled(
false);
1051 CallableSystemAction
1052 .get(CasePropertiesAction.class
1053 ).setEnabled(
false);
1054 CallableSystemAction
1055 .get(CaseDeleteAction.class
1056 ).setEnabled(
false);
1057 CallableSystemAction
1059 ).setEnabled(
false);
1060 CallableSystemAction
1062 ).setEnabled(
false);
1083 File tempFolder =
new File(tempSubDirPath);
1084 if (tempFolder.isDirectory()) {
1085 File[] files = tempFolder.listFiles();
1086 if (files.length > 0) {
1087 for (File file : files) {
1088 if (file.isDirectory()) {
1131 return metadata.getCreatedDate();
1193 hostPath = Paths.get(caseDirectory);
1195 if (!hostPath.toFile().exists()) {
1196 hostPath.toFile().mkdirs();
1198 return hostPath.toString();
1271 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1273 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1287 List<Content> list = caseDb.getRootObjects();
1288 hasDataSources = (list.size() > 0);
1298 Set<TimeZone> timezones =
new HashSet<>();
1301 final Content dataSource = c.getDataSource();
1302 if ((dataSource != null) && (dataSource instanceof Image)) {
1303 Image image = (Image) dataSource;
1304 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1307 }
catch (TskCoreException ex) {
1308 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1330 if (!hasDataSources) {
1333 }
catch (TskCoreException ex) {
1334 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1438 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1439 String normalizedLocalPath;
1441 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1442 }
catch (InvalidPathException ex) {
1443 String errorMsg =
"Invalid local path provided: " + localPath;
1444 throw new TskCoreException(errorMsg, ex);
1446 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName);
1459 return this.caseDb.getAllReports();
1470 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1471 for (Report report : reports) {
1472 this.caseDb.deleteReport(report);
1490 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata, cannot change case display name."
1492 void updateDisplayName(String newDisplayName)
throws CaseActionException {
1495 metadata.setCaseDisplayName(newDisplayName);
1496 }
catch (CaseMetadataException ex) {
1497 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError());
1499 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldDisplayName, newDisplayName));
1500 if (RuntimeProperties.runningWithGUI()) {
1501 SwingUtilities.invokeLater(() -> {
1502 mainFrame.setTitle(newDisplayName +
" - " + UserPreferences.getAppName());
1504 RecentCases.getInstance().updateRecentCase(oldDisplayName, metadata.getFilePath().toString(), newDisplayName, metadata.getFilePath().toString());
1505 }
catch (Exception ex) {
1506 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1526 private Case(
CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) {
1536 metadata = caseMetaData;
1555 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1556 "Case.progressIndicatorTitle.openingCase=Opening Case",
1557 "Case.progressIndicatorCancelButton.label=Cancel",
1558 "Case.progressMessage.preparing=Preparing...",
1559 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1560 "Case.progressMessage.cancelling=Cancelling...",
1561 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1562 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1573 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1576 progressIndicatorTitle,
1577 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1578 Bundle.Case_progressIndicatorCancelButton_label(),
1579 cancelButtonListener);
1583 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1601 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1602 Future<Void> future = caseLockingExecutor.submit(() -> {
1604 open(isNewCase, progressIndicator);
1613 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1616 assert (null != resourcesLock);
1617 open(isNewCase, progressIndicator);
1625 if (null != cancelButtonListener) {
1634 }
catch (InterruptedException discarded) {
1643 if (null != cancelButtonListener) {
1646 future.cancel(
true);
1649 }
catch (CancellationException discarded) {
1659 }
catch (ExecutionException ex) {
1668 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1670 progressIndicator.
finish();
1687 if (Thread.currentThread().isInterrupted()) {
1697 if (Thread.currentThread().isInterrupted()) {
1703 if (Thread.currentThread().isInterrupted()) {
1715 }
catch (InterruptedException discarded) {
1717 close(progressIndicator);
1733 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1734 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1735 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1736 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1746 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1753 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1762 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1770 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1772 }
catch (TskCoreException ex) {
1773 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1777 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1792 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1793 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database.",
1794 "Case.unsupportedSchemaVersionMessage=Unsupported DB schema version - see log for details",
1795 "Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-User.",
1796 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. "
1797 +
"See Tools, Options, Multi-user."
1801 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1804 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1814 }
catch (TskUnsupportedSchemaVersionException ex) {
1816 }
catch (TskCoreException ex) {
1817 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
1830 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
1831 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
1832 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
1833 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
1834 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
1840 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
1842 if (Thread.currentThread().isInterrupted()) {
1849 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
1851 if (Thread.currentThread().isInterrupted()) {
1858 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
1859 this.caseServices =
new Services(caseDb);
1860 if (Thread.currentThread().isInterrupted()) {
1868 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
1870 if (Thread.currentThread().isInterrupted()) {
1879 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
1882 if (Thread.currentThread().isInterrupted()) {
1885 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
1892 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
1895 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
1896 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
1906 @NbBundle.Messages({
1907 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
1908 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
1909 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
1929 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
1932 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
1933 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1934 Bundle.Case_progressIndicatorCancelButton_label(),
1935 cancelButtonListener);
1939 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1941 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
1942 threadNameSuffix = threadNameSuffix.toLowerCase();
1944 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
1945 Future<Void> future = executor.submit(() -> {
1946 service.openCaseResources(context);
1949 if (null != cancelButtonListener) {
1961 }
catch (InterruptedException discarded) {
1966 future.cancel(
true);
1967 }
catch (CancellationException discarded) {
1975 }
catch (ExecutionException ex) {
1982 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
1984 SwingUtilities.invokeLater(() -> {
1996 progressIndicator.
finish();
1999 if (Thread.currentThread().isInterrupted()) {
2017 Bundle.Case_progressIndicatorTitle_closingCase());
2021 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2030 Future<Void> future = caseLockingExecutor.submit(() -> {
2032 close(progressIndicator);
2039 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2041 assert (null != resourcesLock);
2042 close(progressIndicator);
2056 }
catch (InterruptedException | CancellationException unused) {
2063 }
catch (ExecutionException ex) {
2064 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2067 progressIndicator.
finish();
2077 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2078 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2079 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2080 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2090 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2091 if (null != collaborationMonitor) {
2092 collaborationMonitor.shutdown();
2101 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2107 if (null != caseServices) {
2108 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2110 this.caseServices.
close();
2111 }
catch (IOException ex) {
2112 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2119 if (null != caseDb) {
2120 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2127 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2136 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2137 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2149 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2153 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2155 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2156 threadNameSuffix = threadNameSuffix.toLowerCase();
2158 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2159 Future<Void> future = executor.submit(() -> {
2160 service.closeCaseResources(context);
2165 }
catch (InterruptedException ex) {
2166 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2167 }
catch (CancellationException ex) {
2168 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2169 }
catch (ExecutionException ex) {
2170 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2173 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2174 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2178 progressIndicator.
finish();
2191 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2199 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2214 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2227 if (!subDirectory.exists()) {
2228 subDirectory.mkdirs();
2230 return subDirectory.toString();
2243 executor.shutdown();
2244 boolean taskCompleted =
false;
2245 while (!taskCompleted) {
2247 taskCompleted = executor.awaitTermination(EXECUTOR_AWAIT_TIMEOUT_SECS, TimeUnit.SECONDS);
2248 }
catch (InterruptedException ignored) {
2356 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2385 return new Thread(task, threadName);
2520 return new File(filePath).isFile();
2559 return "ModuleOutput";
2572 public static PropertyChangeSupport
2574 return new PropertyChangeSupport(
Case.class
2608 Image newDataSource = caseDb.getImageById(imgId);
2610 return newDataSource;
2611 }
catch (TskCoreException ex) {
2612 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2639 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 void shutDownTaskExecutor(ExecutorService executor)
static final String CASE_ACTION_THREAD_NAME
void publishLocally(AutopsyEvent event)
Case(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner)
void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag)
Set< TimeZone > getTimeZones()
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()
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)
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 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)
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)
static final long EXECUTOR_AWAIT_TIMEOUT_SECS
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)
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 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)