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;
116 import org.
sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
154 WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
157 mainFrame = WindowManager.getDefault().getMainWindow();
180 if (typeName != null) {
182 if (typeName.equalsIgnoreCase(c.toString())) {
206 "Case_caseType_singleUser=Single-user case",
207 "Case_caseType_multiUser=Multi-user case"
210 if (fromString(typeName) == SINGLE_USER_CASE) {
211 return Bundle.Case_caseType_singleUser();
213 return Bundle.Case_caseType_multiUser();
223 this.typeName = typeName;
238 return (otherTypeName == null) ?
false : typeName.equals(otherTypeName);
384 .map(Events::toString)
385 .collect(Collectors.toSet()), listener);
396 .map(Events::toString)
397 .collect(Collectors.toSet()), listener);
420 eventTypes.forEach((
Events event) -> {
465 eventTypes.forEach((
Events event) -> {
479 return !(caseName.contains(
"\\") || caseName.contains(
"/") || caseName.contains(
":")
480 || caseName.contains(
"*") || caseName.contains(
"?") || caseName.contains(
"\"")
481 || caseName.contains(
"<") || caseName.contains(
">") || caseName.contains(
"|"));
533 "Case.exceptionMessage.emptyCaseName=Must specify a case name.",
534 "Case.exceptionMessage.emptyCaseDir=Must specify a case directory path."
538 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName());
540 if (caseDir.isEmpty()) {
541 throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseDir());
560 "Case.exceptionMessage.failedToReadMetadata=Failed to read case metadata.",
561 "Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case."
566 metadata =
new CaseMetadata(Paths.get(caseMetadataFilePath));
568 throw new CaseActionException(Bundle.Case_exceptionMessage_failedToReadMetadata(), ex);
571 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotOpenMultiUserCaseNoSettings());
582 return currentCase != null;
600 if (null != currentCase) {
603 throw new IllegalStateException(NbBundle.getMessage(
Case.class,
"Case.getCurCase.exception.noneOpen"));
616 "# {0} - exception message",
"Case.closeException.couldNotCloseCase=Error closing case: {0}",
617 "Case.progressIndicatorTitle.closingCase=Closing Case"
621 if (null == currentCase) {
627 logger.log(Level.INFO,
"Closing current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
630 logger.log(Level.INFO,
"Closed current case {0} ({1}) in {2}",
new Object[]{closedCase.getDisplayName(), closedCase.getName(), closedCase.getCaseDirectory()});
631 }
catch (CaseActionException ex) {
652 if (null == currentCase) {
673 "Case.progressIndicatorTitle.deletingCase=Deleting Case",
674 "Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it must be closed first.",
675 "Case.progressMessage.checkingForOtherUser=Checking to see if another user has the case open...",
676 "Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
680 if (null != currentCase) {
681 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
695 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
704 progressIndicator.
progress(Bundle.Case_progressMessage_checkingForOtherUser());
706 assert (null != dirLock);
709 throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
713 progressIndicator.
finish();
728 "Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window"
732 if (null != currentCase) {
735 }
catch (CaseActionException ex) {
744 logger.log(Level.INFO,
"Opening {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
745 newCurrentCase.
open(isNewCase);
746 currentCase = newCurrentCase;
747 logger.log(Level.INFO,
"Opened {0} ({1}) in {2} as the current case",
new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()});
753 logger.log(Level.INFO, String.format(
"Cancelled opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()));
755 }
catch (CaseActionException ex) {
756 logger.log(Level.SEVERE, String.format(
"Error opening %s (%s) in %s as the current case", newCurrentCase.
getDisplayName(), newCurrentCase.
getName(), newCurrentCase.
getCaseDirectory()), ex);
774 String uniqueCaseName = caseDisplayName.replaceAll(
"[^\\p{ASCII}]",
"_");
779 uniqueCaseName = uniqueCaseName.replaceAll(
"[\\p{Cntrl}]",
"_");
784 uniqueCaseName = uniqueCaseName.replaceAll(
"[ /?:'\"\\\\]",
"_");
789 uniqueCaseName = uniqueCaseName.toLowerCase();
794 SimpleDateFormat dateFormat =
new SimpleDateFormat(
"yyyyMMdd_HHmmss");
795 Date date =
new Date();
796 uniqueCaseName = uniqueCaseName +
"_" + dateFormat.format(date);
798 return uniqueCaseName;
809 static void createCaseDirectory(String caseDir,
CaseType caseType)
throws CaseActionException {
811 File caseDirF =
new File(caseDir);
813 if (caseDirF.exists()) {
814 if (caseDirF.isFile()) {
815 throw new CaseActionException(
816 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existNotDir", caseDir));
818 }
else if (!caseDirF.canRead() || !caseDirF.canWrite()) {
819 throw new CaseActionException(
820 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.existCantRW", caseDir));
825 boolean result = (caseDirF).mkdirs();
827 if (result ==
false) {
828 throw new CaseActionException(
829 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreate", caseDir));
833 String hostClause =
"";
836 hostClause = File.separator + NetworkUtils.getLocalHostName();
838 result = result && (
new File(caseDir + hostClause + File.separator + EXPORT_FOLDER)).mkdirs()
839 && (
new File(caseDir + hostClause + File.separator + LOG_FOLDER)).mkdirs()
840 && (
new File(caseDir + hostClause + File.separator + TEMP_FOLDER)).mkdirs()
841 && (
new File(caseDir + hostClause + File.separator + CACHE_FOLDER)).mkdirs();
843 if (result ==
false) {
844 throw new CaseActionException(
845 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateCaseDir", caseDir));
848 final String modulesOutDir = caseDir + hostClause + File.separator +
MODULE_FOLDER;
849 result =
new File(modulesOutDir).mkdir();
851 if (result ==
false) {
852 throw new CaseActionException(
853 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateModDir",
857 final String reportsOutDir = caseDir + hostClause + File.separator +
REPORTS_FOLDER;
858 result =
new File(reportsOutDir).mkdir();
860 if (result ==
false) {
861 throw new CaseActionException(
862 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.cantCreateReportsDir",
867 }
catch (MissingResourceException | CaseActionException e) {
868 throw new CaseActionException(
869 NbBundle.getMessage(
Case.class,
"Case.createCaseDir.exception.gen", caseDir), e);
880 static Map<Long, String> getImagePaths(SleuthkitCase db) {
881 Map<Long, String> imgPaths =
new HashMap<>();
883 Map<Long, List<String>> imgPathsList = db.getImagePaths();
884 for (Map.Entry<Long, List<String>> entry : imgPathsList.entrySet()) {
885 if (entry.getValue().size() > 0) {
886 imgPaths.put(entry.getKey(), entry.getValue().get(0));
889 }
catch (TskCoreException ex) {
890 logger.log(Level.SEVERE,
"Error getting image paths", ex);
912 "Case.progressMessage.deletingTextIndex=Deleting text index...",
913 "Case.progressMessage.deletingCaseDatabase=Deleting case database...",
914 "Case.progressMessage.deletingCaseDirectory=Deleting case directory...",
915 "Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
918 boolean errorsOccurred =
false;
924 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDatabase());
925 CaseDbConnectionInfo db;
927 Class.forName(
"org.postgresql.Driver");
928 try (Connection connection = DriverManager.getConnection(
"jdbc:postgresql://" + db.getHost() +
":" + db.getPort() +
"/postgres", db.getUserName(), db.getPassword());
929 Statement statement = connection.createStatement();) {
931 statement.execute(deleteCommand);
935 errorsOccurred =
true;
942 progressIndicator.
progress(Bundle.Case_progressMessage_deletingTextIndex());
945 searchService.deleteTextIndex(metadata);
948 errorsOccurred =
true;
955 progressIndicator.
progress(Bundle.Case_progressMessage_deletingCaseDirectory());
958 errorsOccurred =
true;
965 SwingUtilities.invokeLater(() -> {
966 RecentCases.getInstance().removeRecentCase(metadata.
getCaseDisplayName(), metadata.getFilePath().toString());
970 if (errorsOccurred) {
971 throw new CaseActionException(Bundle.Case_exceptionMessage_errorsDeletingCase());
985 @Messages({
"Case.creationException.couldNotAcquireResourcesLock=Failed to get lock on case resources"})
988 String resourcesNodeName = caseDir +
"_resources";
991 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
994 }
catch (InterruptedException ex) {
997 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock(), ex);
1017 SwingUtilities.invokeLater(() -> {
1023 String backupDbPath = caseDb.getBackupDatabasePath();
1024 if (null != backupDbPath) {
1025 JOptionPane.showMessageDialog(
1027 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.msg", backupDbPath),
1028 NbBundle.getMessage(
Case.class,
"Case.open.msgDlg.updated.title"),
1029 JOptionPane.INFORMATION_MESSAGE);
1037 Map<Long, String> imgPaths = getImagePaths(caseDb);
1038 for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
1039 long obj_id = entry.getKey();
1040 String path = entry.getValue();
1043 int response = JOptionPane.showConfirmDialog(
1045 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.msg", path),
1046 NbBundle.getMessage(
Case.class,
"Case.checkImgExist.confDlg.doesntExist.title"),
1047 JOptionPane.YES_NO_OPTION);
1048 if (response == JOptionPane.YES_OPTION) {
1049 MissingImageDialog.makeDialog(obj_id, caseDb);
1051 logger.log(Level.SEVERE,
"User proceeding with missing image files");
1062 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
true);
1063 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
true);
1073 RecentCases.getInstance().addRecentCase(newCurrentCase.
getDisplayName(), newCurrentCase.getMetadata().getFilePath().toString());
1079 if (newCurrentCase.
hasData()) {
1098 SwingUtilities.invokeLater(() -> {
1108 CallableSystemAction.get(
AddImageAction.class).setEnabled(
false);
1110 CallableSystemAction.get(CasePropertiesAction.class).setEnabled(
false);
1111 CallableSystemAction.get(CaseDeleteAction.class).setEnabled(
false);
1135 File tempFolder =
new File(tempSubDirPath);
1136 if (tempFolder.isDirectory()) {
1137 File[] files = tempFolder.listFiles();
1138 if (files.length > 0) {
1139 for (File file : files) {
1140 if (file.isDirectory()) {
1183 return metadata.getCreatedDate();
1272 hostPath = Paths.get(caseDirectory);
1274 if (!hostPath.toFile().exists()) {
1275 hostPath.toFile().mkdirs();
1277 return hostPath.toString();
1350 return path.subpath(path.getNameCount() - 2, path.getNameCount()).toString();
1352 return path.subpath(path.getNameCount() - 1, path.getNameCount()).toString();
1366 List<Content> list = caseDb.getRootObjects();
1367 hasDataSources = (list.size() > 0);
1377 Set<TimeZone> timezones =
new HashSet<>();
1380 final Content dataSource = c.getDataSource();
1381 if ((dataSource != null) && (dataSource instanceof Image)) {
1382 Image image = (Image) dataSource;
1383 timezones.add(TimeZone.getTimeZone(image.getTimeZone()));
1386 }
catch (TskCoreException ex) {
1387 logger.log(Level.SEVERE,
"Error getting data source time zones", ex);
1409 if (!hasDataSources) {
1412 }
catch (TskCoreException ex) {
1413 logger.log(Level.SEVERE,
"Error accessing case database", ex);
1529 public void addReport(String localPath, String srcModuleName, String reportName)
throws TskCoreException {
1530 String normalizedLocalPath;
1532 normalizedLocalPath = Paths.get(localPath).normalize().toString();
1533 }
catch (InvalidPathException ex) {
1534 String errorMsg =
"Invalid local path provided: " + localPath;
1535 throw new TskCoreException(errorMsg, ex);
1537 Report report = this.caseDb.addReport(normalizedLocalPath, srcModuleName, reportName);
1550 return this.caseDb.getAllReports();
1561 public void deleteReports(Collection<? extends Report> reports)
throws TskCoreException {
1562 for (Report report : reports) {
1563 this.caseDb.deleteReport(report);
1585 "Case.exceptionMessage.metadataUpdateError=Failed to update case metadata"
1587 void updateCaseDetails(CaseDetails caseDetails)
throws CaseActionException {
1590 metadata.setCaseDetails(caseDetails);
1591 }
catch (CaseMetadataException ex) {
1592 throw new CaseActionException(Bundle.Case_exceptionMessage_metadataUpdateError(), ex);
1594 if (!oldCaseDetails.getCaseNumber().equals(caseDetails.
getCaseNumber())) {
1595 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getCaseNumber(), caseDetails.
getCaseNumber()));
1597 if (!oldCaseDetails.getExaminerName().equals(caseDetails.
getExaminerName())) {
1598 eventPublisher.
publish(
new AutopsyEvent(Events.NUMBER.toString(), oldCaseDetails.getExaminerName(), caseDetails.
getExaminerName()));
1601 eventPublisher.
publish(
new AutopsyEvent(Events.NAME.toString(), oldCaseDetails.getCaseDisplayName(), caseDetails.
getCaseDisplayName()));
1603 eventPublisher.
publish(
new AutopsyEvent(Events.CASE_DETAILS.toString(), oldCaseDetails, caseDetails));
1604 if (RuntimeProperties.runningWithGUI()) {
1605 SwingUtilities.invokeLater(() -> {
1608 RecentCases.getInstance().updateRecentCase(oldCaseDetails.getCaseDisplayName(), metadata.getFilePath().toString(), caseDetails.
getCaseDisplayName(), metadata.getFilePath().toString());
1609 }
catch (Exception ex) {
1610 logger.log(Level.SEVERE,
"Error updating case name in UI", ex);
1637 metadata = caseMetaData;
1656 "Case.progressIndicatorTitle.creatingCase=Creating Case",
1657 "Case.progressIndicatorTitle.openingCase=Opening Case",
1658 "Case.progressIndicatorCancelButton.label=Cancel",
1659 "Case.progressMessage.preparing=Preparing...",
1660 "Case.progressMessage.preparingToOpenCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>",
1661 "Case.progressMessage.cancelling=Cancelling...",
1662 "Case.exceptionMessage.cancelledByUser=Cancelled by user.",
1663 "# {0} - exception message",
"Case.exceptionMessage.execExceptionWrapperMessage={0}"
1665 private void open(
boolean isNewCase)
throws CaseActionException {
1674 String progressIndicatorTitle = isNewCase ? Bundle.Case_progressIndicatorTitle_creatingCase() : Bundle.Case_progressIndicatorTitle_openingCase();
1677 progressIndicatorTitle,
1678 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
1679 Bundle.Case_progressIndicatorCancelButton_label(),
1680 cancelButtonListener);
1684 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
1702 caseLockingExecutor = Executors.newSingleThreadExecutor(threadFactory);
1703 Future<Void> future = caseLockingExecutor.submit(() -> {
1705 open(isNewCase, progressIndicator);
1714 progressIndicator.
progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
1717 assert (null != resourcesLock);
1718 open(isNewCase, progressIndicator);
1719 }
catch (CaseActionException ex) {
1726 if (null != cancelButtonListener) {
1735 }
catch (InterruptedException discarded) {
1744 if (null != cancelButtonListener) {
1747 future.cancel(
true);
1750 }
catch (CancellationException discarded) {
1760 }
catch (ExecutionException ex) {
1769 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getLocalizedMessage()), ex);
1771 progressIndicator.
finish();
1788 if (Thread.currentThread().isInterrupted()) {
1798 if (Thread.currentThread().isInterrupted()) {
1804 if (Thread.currentThread().isInterrupted()) {
1807 }
catch (CaseActionException ex) {
1816 }
catch (InterruptedException discarded) {
1818 close(progressIndicator);
1834 "Case.progressMessage.creatingCaseDirectory=Creating case directory...",
1835 "Case.progressMessage.creatingCaseDatabase=Creating case database...",
1836 "# {0} - exception message",
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database:\n{0}",
1837 "Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file."
1847 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDirectory());
1854 progressIndicator.
progress(Bundle.Case_progressMessage_creatingCaseDatabase());
1863 metadata.setCaseDatabaseName(SINGLE_USER_CASE_DB_NAME);
1871 metadata.setCaseDatabaseName(caseDb.getDatabaseName());
1873 }
catch (TskCoreException ex) {
1874 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(ex.getLocalizedMessage()), ex);
1876 throw new CaseActionException(NbBundle.getMessage(
Case.class,
"Case.databaseConnectionInfo.error.msg"), ex);
1878 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateMetadataFile(), ex);
1893 "Case.progressMessage.openingCaseDatabase=Opening case database...",
1894 "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database.",
1895 "Case.unsupportedSchemaVersionMessage=Unsupported DB schema version - see log for details",
1896 "Case.databaseConnectionInfo.error.msg=Error accessing database server connection info. See Tools, Options, Multi-User.",
1897 "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. "
1898 +
"See Tools, Options, Multi-user."
1902 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseDatabase());
1905 caseDb = SleuthkitCase.openCase(Paths.get(metadata.
getCaseDirectory(), databaseName).toString());
1910 throw new CaseActionException(Case_databaseConnectionInfo_error_msg(), ex);
1913 throw new CaseActionException(Case_open_exception_multiUserCaseNotEnabled());
1915 }
catch (TskUnsupportedSchemaVersionException ex) {
1916 throw new CaseActionException(Bundle.Case_unsupportedSchemaVersionMessage(), ex);
1917 }
catch (TskCoreException ex) {
1918 throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotOpenCaseDatabase(), ex);
1931 "Case.progressMessage.switchingLogDirectory=Switching log directory...",
1932 "Case.progressMessage.clearingTempDirectory=Clearing case temp directory...",
1933 "Case.progressMessage.openingCaseLevelServices=Opening case-level services...",
1934 "Case.progressMessage.openingApplicationServiceResources=Opening application service case resources...",
1935 "Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
1941 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
1943 if (Thread.currentThread().isInterrupted()) {
1950 progressIndicator.
progress(Bundle.Case_progressMessage_clearingTempDirectory());
1952 if (Thread.currentThread().isInterrupted()) {
1959 progressIndicator.
progress(Bundle.Case_progressMessage_openingCaseLevelServices());
1960 this.caseServices =
new Services(caseDb);
1961 if (Thread.currentThread().isInterrupted()) {
1969 progressIndicator.
progress(Bundle.Case_progressMessage_openingApplicationServiceResources());
1971 if (Thread.currentThread().isInterrupted()) {
1980 progressIndicator.
progress(Bundle.Case_progressMessage_settingUpNetworkCommunications());
1983 if (Thread.currentThread().isInterrupted()) {
1986 collaborationMonitor =
new CollaborationMonitor(metadata.
getCaseName());
1993 logger.log(Level.SEVERE,
"Failed to setup network communications", ex);
1996 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.Title"),
1997 NbBundle.getMessage(
Case.class,
"Case.CollaborationSetup.FailNotify.ErrMsg")));
2007 @NbBundle.Messages({
2008 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.title={0} Opening Case Resources",
2009 "# {0} - service name",
"Case.serviceOpenCaseResourcesProgressIndicator.cancellingMessage=Cancelling opening case resources by {0}...",
2010 "# {0} - service name",
"Case.servicesException.notificationTitle={0} Error"
2030 cancelButtonListener =
new CancelButtonListener(Bundle.Case_serviceOpenCaseResourcesProgressIndicator_cancellingMessage(service.getServiceName()));
2033 Bundle.Case_serviceOpenCaseResourcesProgressIndicator_title(service.getServiceName()),
2034 new String[]{Bundle.Case_progressIndicatorCancelButton_label()},
2035 Bundle.Case_progressIndicatorCancelButton_label(),
2036 cancelButtonListener);
2040 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2042 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2043 threadNameSuffix = threadNameSuffix.toLowerCase();
2045 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2046 Future<Void> future = executor.submit(() -> {
2047 service.openCaseResources(context);
2050 if (null != cancelButtonListener) {
2062 }
catch (InterruptedException discarded) {
2067 future.cancel(
true);
2068 }
catch (CancellationException discarded) {
2076 }
catch (ExecutionException ex) {
2083 Case.
logger.log(Level.SEVERE, String.format(
"%s failed to open case resources for %s", service.getServiceName(), this.
getDisplayName()), ex);
2085 SwingUtilities.invokeLater(() -> {
2097 progressIndicator.
finish();
2100 if (Thread.currentThread().isInterrupted()) {
2109 private void close() throws CaseActionException {
2118 Bundle.Case_progressIndicatorTitle_closingCase());
2122 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2131 Future<Void> future = caseLockingExecutor.submit(() -> {
2133 close(progressIndicator);
2140 progressIndicator.
progress(Bundle.Case_progressMessage_preparing());
2142 assert (null != resourcesLock);
2143 close(progressIndicator);
2157 }
catch (InterruptedException | CancellationException unused) {
2164 }
catch (ExecutionException ex) {
2165 throw new CaseActionException(Bundle.Case_exceptionMessage_execExceptionWrapperMessage(ex.getCause().getMessage()), ex);
2168 progressIndicator.
finish();
2178 "Case.progressMessage.shuttingDownNetworkCommunications=Shutting down network communications...",
2179 "Case.progressMessage.closingApplicationServiceResources=Closing case-specific application service resources...",
2180 "Case.progressMessage.closingCaseLevelServices=Closing case-level services...",
2181 "Case.progressMessage.closingCaseDatabase=Closing case database..."
2191 progressIndicator.
progress(Bundle.Case_progressMessage_shuttingDownNetworkCommunications());
2192 if (null != collaborationMonitor) {
2193 collaborationMonitor.shutdown();
2202 progressIndicator.
progress(Bundle.Case_progressMessage_closingApplicationServiceResources());
2208 if (null != caseServices) {
2209 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseLevelServices());
2211 this.caseServices.
close();
2212 }
catch (IOException ex) {
2213 logger.log(Level.SEVERE, String.format(
"Error closing internal case services for %s at %s",
this.getName(), this.
getCaseDirectory()), ex);
2220 if (null != caseDb) {
2221 progressIndicator.
progress(Bundle.Case_progressMessage_closingCaseDatabase());
2228 progressIndicator.
progress(Bundle.Case_progressMessage_switchingLogDirectory());
2237 "# {0} - serviceName",
"Case.serviceCloseResourcesProgressIndicator.title={0} Closing Case Resources",
2238 "# {0} - service name",
"# {1} - exception message",
"Case.servicesException.serviceResourcesCloseError=Could not close case resources for {0} service: {1}"
2250 Bundle.Case_serviceCloseResourcesProgressIndicator_title(service.getServiceName()));
2254 progressIndicator.
start(Bundle.Case_progressMessage_preparing());
2256 String threadNameSuffix = service.getServiceName().replaceAll(
"[ ]",
"-");
2257 threadNameSuffix = threadNameSuffix.toLowerCase();
2259 ExecutorService executor = Executors.newSingleThreadExecutor(threadFactory);
2260 Future<Void> future = executor.submit(() -> {
2261 service.closeCaseResources(context);
2266 }
catch (InterruptedException ex) {
2267 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected interrupt while waiting on %s service to close case resources", service.getServiceName()), ex);
2268 }
catch (CancellationException ex) {
2269 Case.
logger.log(Level.SEVERE, String.format(
"Unexpected cancellation while waiting on %s service to close case resources", service.getServiceName()), ex);
2270 }
catch (ExecutionException ex) {
2271 Case.
logger.log(Level.SEVERE, String.format(
"%s service failed to open case resources", service.getServiceName()), ex);
2274 Bundle.Case_servicesException_notificationTitle(service.getServiceName()),
2275 Bundle.Case_servicesException_serviceResourcesCloseError(service.getServiceName(), ex.getLocalizedMessage())));
2279 progressIndicator.
finish();
2292 @Messages({
"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
2297 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
2300 throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock(), ex);
2315 logger.log(Level.SEVERE, String.format(
"Failed to release shared case directory lock for %s", caseDir), ex);
2328 if (!subDirectory.exists()) {
2329 subDirectory.mkdirs();
2331 return subDirectory.toString();
2422 ((ModalDialogProgressIndicator) progressIndicator).setCancelling(cancellationMessage);
2451 return new Thread(task, threadName);
2488 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
throws CaseActionException {
2513 public static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner,
CaseType caseType)
throws CaseActionException {
2529 public static void open(String caseMetadataFilePath)
throws CaseActionException {
2586 return new File(filePath).isFile();
2625 return "ModuleOutput";
2638 public static PropertyChangeSupport
2640 return new PropertyChangeSupport(
Case.class
2672 public Image
addImage(String imgPath,
long imgId, String timeZone)
throws CaseActionException {
2674 Image newDataSource = caseDb.getImageById(imgId);
2676 return newDataSource;
2677 }
catch (TskCoreException ex) {
2678 throw new CaseActionException(NbBundle.getMessage(
this.getClass(),
"Case.addImg.exception.msg"), ex);
2705 public void deleteReports(Collection<? extends Report> reports,
boolean deleteFromDisk)
throws TskCoreException {
String getLogDirectoryPath()
static final AutopsyEventPublisher eventPublisher
List< Content > getDataSources()
String getModuleOutputDirectoryRelativePath()
void notifyContentTagDeleted(ContentTag deletedTag)
Case(CaseMetadata caseMetaData)
static CaseType fromString(String typeName)
static final String CASE_ACTION_THREAD_NAME
void publishLocally(AutopsyEvent event)
static void createAsCurrentCase(CaseType caseType, String caseDir, CaseDetails caseDetails)
void notifyBlackBoardArtifactTagDeleted(BlackboardArtifactTag deletedTag)
String getExaminerPhone()
Set< TimeZone > getTimeZones()
static String getNameForTitle()
Image addImage(String imgPath, long imgId, String timeZone)
static synchronized IngestManager getInstance()
static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir)
static boolean runningWithGUI
static void closeCurrentCase()
String getTempDirectory()
static boolean existsCurrentCase()
static void removePropertyChangeListener(PropertyChangeListener listener)
void start(String message, int totalWorkUnits)
static final Logger logger
void publish(AutopsyEvent event)
static final int RESOURCES_LOCK_TIMOUT_HOURS
String getLocalizedDisplayName()
ADDING_DATA_SOURCE_FAILED
static final String EXPORT_FOLDER
String getCaseDirectory()
static String getAppName()
void notifyTagDefinitionChanged(String changedTagName)
static volatile Frame mainFrame
static String convertTimeZone(String timeZoneId)
static boolean driveExists(String path)
static void openCoreWindows()
void addSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
synchronized static void setLogDirectory(String directoryPath)
TaskThreadFactory(String threadName)
static final String CACHE_FOLDER
static String getAutopsyVersion()
CaseType(String typeName)
Case(CaseType caseType, String caseDir, CaseDetails caseDetails)
String getReportDirectory()
void createCaseData(ProgressIndicator progressIndicator)
static boolean getIsMultiUserModeEnabled()
void addReport(String localPath, String srcModuleName, String reportName)
static void updateGUIForCaseOpened(Case newCurrentCase)
static CaseDbConnectionInfo getDatabaseConnectionInfo()
String getModulesOutputDirAbsPath()
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
void closeAppServiceCaseResources()
static final String SINGLE_USER_CASE_DB_NAME
static void deleteCase(CaseMetadata metadata)
void deleteReports(Collection<?extends Report > reports, boolean deleteFromDisk)
synchronized void closeRemoteEventChannel()
volatile ExecutorService caseLockingExecutor
List< Report > getAllReports()
static void clearTempSubDir(String tempSubDirPath)
static boolean isValidName(String caseName)
void acquireSharedCaseDirLock(String caseDir)
CollaborationMonitor collaborationMonitor
void releaseSharedCaseDirLock(String caseDir)
static void shutDownTaskExecutor(ExecutorService executor)
static void closeCoreWindows()
ProgressIndicator getProgressIndicator()
static String getModulesOutputDirRelPath()
Set< TimeZone > getTimeZone()
void openCaseData(ProgressIndicator progressIndicator)
static final String MODULE_FOLDER
static void create(String caseDir, String caseDisplayName, String caseNumber, String examiner)
synchronized void openRemoteEventChannel(String channelName)
String getCaseDisplayName()
void openAppServiceCaseResources()
void openServices(ProgressIndicator progressIndicator)
static void invokeStartupDialog()
static String displayNameToUniqueName(String caseDisplayName)
void open(boolean isNewCase)
static void openAsCurrentCase(String caseMetadataFilePath)
static void removeEventSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
Lock tryGetExclusiveLock(CategoryNode category, String nodePath, int timeOut, TimeUnit timeUnit)
static final int DIR_LOCK_TIMOUT_HOURS
void close(ProgressIndicator progressIndicator)
SleuthkitCase getSleuthkitCase()
void notifyBlackBoardArtifactTagAdded(BlackboardArtifactTag newTag)
static PropertyChangeSupport getPropertyChangeSupport()
String getCacheDirectory()
static void addPropertyChangeListener(PropertyChangeListener listener)
void removeSubscriber(Set< String > eventNames, PropertyChangeListener subscriber)
String getModuleDirectory()
Thread newThread(Runnable task)
static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber)
final CaseMetadata metadata
void deleteReports(Collection<?extends Report > reports)
void notifyDataSourceAdded(Content dataSource, UUID addingDataSourceEventId)
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)
String getExaminerEmail()