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;
152 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
155 mainFrame = WindowManager.getDefault().getMainWindow();
178 if (typeName != null) {
180 if (typeName.equalsIgnoreCase(c.toString())) {
204 "Case_caseType_singleUser=Single-user case",
205 "Case_caseType_multiUser=Multi-user case"
208 if (fromString(typeName) == SINGLE_USER_CASE) {
209 return Bundle.Case_caseType_singleUser();
211 return Bundle.Case_caseType_multiUser();
221 this.typeName = typeName;
236 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
359 .map(Events::toString)
360 .collect(Collectors.toSet()), listener);
371 .map(Events::toString)
372 .collect(Collectors.toSet()), listener);
424 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
425 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
426 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
451 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
452 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
455 if (caseDisplayName.isEmpty()) {
458 if (caseDir.isEmpty()) {
478 "Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata.",
479 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
484 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
489 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
500 return currentCase != null;
518 if (null != currentCase) {
521 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
534 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
535 "Case.progressIndicatorTitle.closingCase=Closing Case"
539 if (null == currentCase) {
545 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
548 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
570 if (null == currentCase) {
591 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
592 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
593 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
594 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
598 if (null != currentCase) {
613 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
622 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
624 assert (null != dirLock);
627 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
631 progressIndicator.
finish();
646 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
650 if (null != currentCase) {
662 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
663 newCurrentCase.
open(isNewCase);
664 currentCase = newCurrentCase;
665 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
671 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
674 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
692 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
697 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
702 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
707 uniqueCaseName = uniqueCaseName.toLowerCase();
712 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
713 Date date =
new Date();
714 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
716 return uniqueCaseName;
729 File caseDirF =
new File(caseDir);
731 if (caseDirF.exists()) {
732 if (caseDirF.isFile()) {
734 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
736 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
737 throw new CaseActionException(
738 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
743 boolean result = (caseDirF).mkdirs();
745 if (result ==
false) {
746 throw new CaseActionException(
747 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
751 String hostClause =
"";
754 hostClause = File.separator + NetworkUtils.getLocalHostName();
756 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
757 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
758 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
759 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
761 if (result ==
false) {
762 throw new CaseActionException(
763 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
766 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
767 result =
new File(modulesOutDir).mkdir();
769 if (result ==
false) {
770 throw new CaseActionException(
771 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
775 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
776 result =
new File(reportsOutDir).mkdir();
778 if (result ==
false) {
779 throw new CaseActionException(
780 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
785 }
catch (MissingResourceException | CaseActionException e) {
786 throw new CaseActionException(
787 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
798 static Map<Long, String> getImagePaths(SleuthkitCase db) {
799 Map<Long, String> imgPaths =
new HashMap<>();
801 Map<Long, List<String>> imgPathsList = db.getImagePaths();
802 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
803 if (entry.getValue().size() > 0) {
804 imgPaths.put(entry.getKey(), entry.getValue().get(0));
807 }
catch (TskCoreException ex) {
808 logger.log(Level.SEVERE,
"Error getting image paths", ex);
830 "Case.progressMessage.deletingTextIndex=Deleting text index...",
831 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
832 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
833 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
836 boolean errorsOccurred =
false;
842 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
843 CaseDbConnectionInfo db;
845 Class.forName(
"org.postgresql.Driver");
846 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
847 Statement statement = connection.createStatement();) {
849 statement.execute(deleteCommand);
853 errorsOccurred =
true;
860 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
863 searchService.deleteTextIndex(metadata);
866 errorsOccurred =
true;
873 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
876 errorsOccurred =
true;
883 SwingUtilities.invokeLater(() -> {
884 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
888 if (errorsOccurred) {
903 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
906 String resourcesNodeName = caseDir +
"_resources";
909 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
912 }
catch (InterruptedException ex) {
915 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
924 SwingUtilities.invokeLater(() -> {
930 String backupDbPath = caseDb.getBackupDatabasePath();
931 if (null != backupDbPath) {
932 JOptionPane.showMessageDialog(
934 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
935 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
936 JOptionPane.INFORMATION_MESSAGE);
944 Map<Long, String> imgPaths = getImagePaths(caseDb);
945 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
946 long obj_id = entry.getKey();
947 String path = entry.getValue();
950 int response = JOptionPane.showConfirmDialog(
952 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
953 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
954 JOptionPane.YES_NO_OPTION);
955 if (response == JOptionPane.YES_OPTION) {
956 MissingImageDialog.makeDialog(obj_id, caseDb);
958 logger.log(Level.SEVERE,
"User proceeding with missing image files");
973 .get(CasePropertiesAction.class
976 .get(CaseDeleteAction.class
990 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
996 if (newCurrentCase.
hasData()) {
1015 SwingUtilities.invokeLater(() -> {
1025 CallableSystemAction
1027 ).setEnabled(
false);
1028 CallableSystemAction
1030 ).setEnabled(
false);
1031 CallableSystemAction
1032 .get(CasePropertiesAction.class
1033 ).setEnabled(
false);
1034 CallableSystemAction
1035 .get(CaseDeleteAction.class
1036 ).setEnabled(
false);
1037 CallableSystemAction
1039 ).setEnabled(
false);
1040 CallableSystemAction
1042 ).setEnabled(
false);
1063 File tempFolder =
new File(tempSubDirPath);
1064 if (tempFolder.isDirectory()) {
1065 File[] files = tempFolder.listFiles();
1066 if (files.length > 0) {
1067 for (File file : files) {
1068 if (file.isDirectory()) {
1111 return metadata.getCreatedDate();
1173 hostPath = Paths.get(caseDirectory);
1175 if (!hostPath.toFile().exists()) {
1176 hostPath.toFile().mkdirs();
1178 return hostPath.toString();
1251 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1253 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1267 List<Content> list = caseDb.getRootObjects();
1268 hasDataSources = (list.size() > 0);
1278 Set<TimeZone> timezones =
new HashSet<>();
1281 final Content dataSource = c.getDataSource();
1282 if ((dataSource != null) && (dataSource instanceof Image)) {
1283 Image image = (Image) dataSource;
1284 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1287 }
catch (TskCoreException ex) {
1288 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1310 if (!hasDataSources) {
1313 }
catch (TskCoreException ex) {
1314 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1418 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1419 String normalizedLocalPath;
1421 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1422 }
catch (InvalidPathException ex) {
1423 String errorMsg =
"Invalid local path provided: " + localPath;
1424 throw new TskCoreException(errorMsg, ex);
1426 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName);
1439 return this.caseDb.getAllReports();
1450 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1451 for (Report report : reports) {
1452 this.caseDb.deleteReport(report);
1470 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata, cannot change case display name."
1472 void updateDisplayName(String newDisplayName)
throws CaseActionException {
1475 metadata.setCaseDisplayName(newDisplayName);
1476 }
catch (CaseMetadataException ex) {
1477 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError());
1479 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldDisplayName, newDisplayName));
1480 if (RuntimeProperties.runningWithGUI()) {
1481 SwingUtilities.invokeLater(() -> {
1482 mainFrame.setTitle(newDisplayName +
" - " + UserPreferences.getAppName());
1484 RecentCases.getInstance().updateRecentCase(oldDisplayName, metadata.getFilePath().toString(), newDisplayName, metadata.getFilePath().toString());
1485 }
catch (Exception ex) {
1486 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1506 private Case(
CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) {
1516 metadata = caseMetaData;
1535 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1536 "Case.progressIndicatorTitle.openingCase=Opening Case",
1537 "Case.progressIndicatorCancelButton.label=Cancel",
1538 "Case.progressMessage.preparing=Preparing...",
1539 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1540 "Case.progressMessage.cancelling=Cancelling...",
1541 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1542 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1553 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1556 progressIndicatorTitle,
1557 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1558 Bundle.Case_progressIndicatorCancelButton_label(),
1559 cancelButtonListener);
1563 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1581 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1582 Future<Void> future = caseLockingExecutor.submit(() -> {
1584 open(isNewCase, progressIndicator);
1593 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1596 assert (null != resourcesLock);
1597 open(isNewCase, progressIndicator);
1605 if (null != cancelButtonListener) {
1614 }
catch (InterruptedException discarded) {
1623 if (null != cancelButtonListener) {
1626 future.cancel(
true);
1629 }
catch (CancellationException discarded) {
1639 }
catch (ExecutionException ex) {
1648 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1650 progressIndicator.
finish();
1667 if (Thread.currentThread().isInterrupted()) {
1677 if (Thread.currentThread().isInterrupted()) {
1683 if (Thread.currentThread().isInterrupted()) {
1695 }
catch (InterruptedException discarded) {
1697 close(progressIndicator);
1713 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1714 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1715 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1716 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1726 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1733 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1742 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1750 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1752 }
catch (TskCoreException ex) {
1753 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1757 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1772 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1773 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database."
1777 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1780 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1787 "Case.databaseConnectionInfo.error.msg"), ex);
1792 "Case.open.exception.multiUserCaseNotEnabled"));
1794 }
catch (TskCoreException ex) {
1795 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
1808 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
1809 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
1810 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
1811 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
1812 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
1818 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
1820 if (Thread.currentThread().isInterrupted()) {
1827 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
1829 if (Thread.currentThread().isInterrupted()) {
1836 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
1837 this.caseServices =
new Services(caseDb);
1838 if (Thread.currentThread().isInterrupted()) {
1846 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
1848 if (Thread.currentThread().isInterrupted()) {
1857 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
1860 if (Thread.currentThread().isInterrupted()) {
1863 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
1870 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
1873 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
1874 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
1884 @NbBundle.Messages({
1885 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
1886 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
1887 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
1907 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
1910 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
1911 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1912 Bundle.Case_progressIndicatorCancelButton_label(),
1913 cancelButtonListener);
1917 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1919 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
1920 threadNameSuffix = threadNameSuffix.toLowerCase();
1922 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
1923 Future<Void> future = executor.submit(() -> {
1924 service.openCaseResources(context);
1927 if (null != cancelButtonListener) {
1939 }
catch (InterruptedException discarded) {
1944 future.cancel(
true);
1945 }
catch (CancellationException discarded) {
1953 }
catch (ExecutionException ex) {
1960 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
1962 SwingUtilities.invokeLater(() -> {
1974 progressIndicator.
finish();
1977 if (Thread.currentThread().isInterrupted()) {
1995 Bundle.Case_progressIndicatorTitle_closingCase());
1999 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2008 Future<Void> future = caseLockingExecutor.submit(() -> {
2010 close(progressIndicator);
2017 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2019 assert (null != resourcesLock);
2020 close(progressIndicator);
2034 }
catch (InterruptedException | CancellationException unused) {
2041 }
catch (ExecutionException ex) {
2042 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2045 progressIndicator.
finish();
2055 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2056 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2057 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2058 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2068 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2069 if (null != collaborationMonitor) {
2070 collaborationMonitor.shutdown();
2079 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2085 if (null != caseServices) {
2086 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2088 this.caseServices.
close();
2089 }
catch (IOException ex) {
2090 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2097 if (null != caseDb) {
2098 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2105 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2114 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2115 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2127 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2131 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2133 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2134 threadNameSuffix = threadNameSuffix.toLowerCase();
2136 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2137 Future<Void> future = executor.submit(() -> {
2138 service.closeCaseResources(context);
2143 }
catch (InterruptedException ex) {
2144 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2145 }
catch (CancellationException ex) {
2146 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2147 }
catch (ExecutionException ex) {
2148 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2151 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2152 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2156 progressIndicator.
finish();
2169 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2177 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2192 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2205 if (!subDirectory.exists()) {
2206 subDirectory.mkdirs();
2208 return subDirectory.toString();
2221 executor.shutdown();
2222 boolean taskCompleted =
false;
2223 while (!taskCompleted) {
2225 taskCompleted = executor.awaitTermination(EXECUTOR_AWAIT_TIMEOUT_SECS, TimeUnit.SECONDS);
2226 }
catch (InterruptedException ignored) {
2334 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2363 return new Thread(task, threadName);
2498 return new File(filePath).isFile();
2537 return "ModuleOutput";
2550 public static PropertyChangeSupport
2552 return new PropertyChangeSupport(
Case.class
2586 Image newDataSource = caseDb.getImageById(imgId);
2588 return newDataSource;
2589 }
catch (TskCoreException ex) {
2590 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2617 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 final int MIN_SECS_BETWEEN_TSK_ERROR_REPORTS
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 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 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)