diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 299af11ea0..3d145a6d4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -256,7 +256,6 @@ public class Case implements SleuthkitCase.ErrorObserver { private String number; private String examiner; private String configFilePath; - private final XMLCaseManagement xmlcm; private final CaseMetadata caseMetadata; private final SleuthkitCase db; // Track the current case (only set with changeCase() method) @@ -286,7 +285,6 @@ public class Case implements SleuthkitCase.ErrorObserver { this.number = number; this.examiner = examiner; this.configFilePath = configFilePath; - this.xmlcm = new XMLCaseManagement(); this.caseMetadata = caseMetadata; this.caseType = type; this.db = db; @@ -509,7 +507,7 @@ public class Case implements SleuthkitCase.ErrorObserver { }); throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseNumber, examiner, caseDir, dbName, indexName); + CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, metadata, db, caseType); changeCase(newCase); @@ -852,7 +850,7 @@ public class Case implements SleuthkitCase.ErrorObserver { changeCase(null); try { services.close(); - this.xmlcm.close(); // close the xmlcm + this.caseMetadata.close(); // close the xmlcm this.db.close(); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.closeCase.exception.msg"), e); @@ -871,7 +869,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { - xmlcm.close(); // close the xmlcm + this.caseMetadata.close(); // close the xmlcm boolean result = deleteCaseDirectory(caseDir); // delete the directory RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath); // remove it from the recent case @@ -899,7 +897,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { - xmlcm.setCaseName(newCaseName); // set the case + caseMetadata.setCaseName(newCaseName); // set the case name = newCaseName; // change the local value eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); SwingUtilities.invokeLater(() -> { @@ -925,7 +923,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateExaminer(String oldExaminer, String newExaminer) throws CaseActionException { try { - xmlcm.setCaseExaminer(newExaminer); // set the examiner + caseMetadata.setCaseExaminer(newExaminer); // set the examiner examiner = newExaminer; eventPublisher.publish(new AutopsyEvent(Events.EXAMINER.toString(), oldExaminer, newExaminer)); } catch (Exception e) { @@ -943,7 +941,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseNumber(String oldCaseNumber, String newCaseNumber) throws CaseActionException { try { - xmlcm.setCaseNumber(newCaseNumber); // set the case number + caseMetadata.setCaseNumber(newCaseNumber); // set the case number number = newCaseNumber; eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber)); } catch (Exception e) { @@ -1032,10 +1030,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getCaseDirectory(); + return caseMetadata.getCaseDirectory(); } } @@ -1234,10 +1232,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return case creation date */ public String getCreatedDate() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getCreatedDate(); + return caseMetadata.getCreatedDate(); } } @@ -1247,10 +1245,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return Index name. */ public String getTextIndexName() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getTextIndexName(); + return caseMetadata.getCaseTextIndexName(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 034f7c41de..581c7f4049 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -99,25 +99,30 @@ public final class CaseMetadata { final static String RELATIVE_TRUE = "true"; // if it's a relative path NON-NLS final static String RELATIVE_FALSE = "false"; // if it's not a relative path NON-NLS - private Document doc; - private final Case.CaseType caseType; - private final String caseName; - private final String caseNumber; - private final String examiner; - private final String caseDirectory; - private final String caseDatabaseName; - private final String caseTextIndexName; + private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); + private Case.CaseType caseType; + private String caseName; + private String caseNumber; + private String examiner; + private String caseDirectory; + private String caseDatabaseName; + private String caseTextIndexName; + private final String createdDate; + private final String schemaVersion; private static final Logger logger = Logger.getLogger(CaseMetadata.class.getName()); - public CaseMetadata(Case.CaseType caseType, String caseName, String caseNumber, String exainer, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + private CaseMetadata(Case.CaseType caseType, String caseName, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { this.caseType = caseType; this.caseName = caseName; - this.caseNumber = caseNumber; - this.examiner = exainer; + this.caseNumber = ""; + this.examiner = ""; + this.createdDate = this.dateFormat.format(new Date()); this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; - this.create(); + this.schemaVersion = "1.0"; + this.write(); + } /** @@ -126,13 +131,17 @@ public final class CaseMetadata { * @param metadataFilePath Path to the metadata (.aut) file for a case. */ public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { + this(metadataFilePath.toString()); + } + + private CaseMetadata(String metadataFilePath) throws CaseMetadataException { try { /* * TODO (RC): This class should eventually replace the non-public * and unsafe XMLCaseManagement class altogether. */ XMLCaseManagement metadata = new XMLCaseManagement(); - metadata.open(metadataFilePath.toString()); + metadata.open(metadataFilePath); try { caseType = metadata.getCaseType(); } catch (NullPointerException unused) { @@ -177,10 +186,32 @@ public final class CaseMetadata { } catch (NullPointerException unused) { throw new CaseMetadataException("Case keyword search index name missing"); } + try { + this.createdDate = metadata.getCreatedDate(); + } catch (NullPointerException unused) { + throw new CaseMetadataException("Case created date element missing"); + } + try { + this.schemaVersion = metadata.getSchemaVersion(); + } catch (NullPointerException unused) { + throw new CaseMetadataException("Case created date element missing"); + } + } catch (CaseActionException ex) { throw new CaseMetadataException(ex.getLocalizedMessage(), ex); } - this.create(); + this.write(); + } + + public static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { + CaseMetadata metadata = new CaseMetadata(metadataFilePath.toString()); + return metadata; + } + + public static CaseMetadata create(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseDirectory, caseDatabaseName, caseTextIndexName); + metadata.write(); + return metadata; } /** @@ -238,15 +269,78 @@ public final class CaseMetadata { } /** - * Gets the text index name. + * Gets the date this case was created * - * @return The case text index name, will be empty for a single-user case. + * @return The date this case was created as a string */ - public String getTextIndexName() { + public String getCreatedDate() { + return this.createdDate; + } + + /** + * @param caseType the caseType to set + */ + public void setCaseType(Case.CaseType caseType) { + this.caseType = caseType; + } + + /** + * @param caseName the caseName to set + */ + public void setCaseName(String caseName) { + this.caseName = caseName; + } + + /** + * @param caseNumber the caseNumber to set + */ + public void setCaseNumber(String caseNumber) { + this.caseNumber = caseNumber; + } + + /** + * @param examiner the examiner to set + */ + public void setCaseExaminer(String examiner) { + this.examiner = examiner; + } + + /** + * @param caseDirectory the caseDirectory to set + */ + public void setCaseDirectory(String caseDirectory) { + this.caseDirectory = caseDirectory; + } + + /** + * @param caseDatabaseName the caseDatabaseName to set + */ + public void setCaseDatabaseName(String caseDatabaseName) { + this.caseDatabaseName = caseDatabaseName; + } + + /** + * @return the caseTextIndexName + */ + public String getCaseTextIndexName() { return caseTextIndexName; } - private void create() throws CaseMetadataException { + /** + * @param caseTextIndexName the caseTextIndexName to set + */ + public void setCaseTextIndexName(String caseTextIndexName) { + this.caseTextIndexName = caseTextIndexName; + } + + /** + * @return the schemaVersion + */ + public String getSchemaVersion() { + return schemaVersion; + } + + private void write() throws CaseMetadataException { DocumentBuilder docBuilder; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); @@ -254,18 +348,16 @@ public final class CaseMetadata { try { docBuilder = docFactory.newDocumentBuilder(); } catch (ParserConfigurationException ex) { - clear(); throw new CaseMetadataException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex); } - DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); - doc = docBuilder.newDocument(); + Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... doc.appendChild(rootElement); Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... - crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); + crDateElement.appendChild(doc.createTextNode(this.getCreatedDate())); rootElement.appendChild(crDateElement); Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... @@ -281,22 +373,22 @@ public final class CaseMetadata { rootElement.appendChild(autSavedVerElement); Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(schemaVersion)); + schVerElement.appendChild(doc.createTextNode(getSchemaVersion())); rootElement.appendChild(schVerElement); Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... rootElement.appendChild(caseElement); Element nameElement = doc.createElement(NAME); // ... - nameElement.appendChild(doc.createTextNode(caseName)); + nameElement.appendChild(doc.createTextNode(getCaseName())); caseElement.appendChild(nameElement); Element numberElement = doc.createElement(NUMBER); // ... - numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber))); + numberElement.appendChild(doc.createTextNode(String.valueOf(getCaseNumber()))); caseElement.appendChild(numberElement); Element examinerElement = doc.createElement(EXAMINER); // ... - examinerElement.appendChild(doc.createTextNode(examiner)); + examinerElement.appendChild(doc.createTextNode(getExaminer())); caseElement.appendChild(examinerElement); Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... @@ -320,21 +412,21 @@ public final class CaseMetadata { caseElement.appendChild(cacheElement); Element typeElement = doc.createElement(CASE_TYPE); // ... - typeElement.appendChild(doc.createTextNode(caseType.toString())); + typeElement.appendChild(doc.createTextNode(getCaseType().toString())); caseElement.appendChild(typeElement); Element dbNameElement = doc.createElement(DATABASE_NAME); // ... - dbNameElement.appendChild(doc.createTextNode(this.caseDatabaseName)); + dbNameElement.appendChild(doc.createTextNode(this.getCaseDatabaseName())); caseElement.appendChild(dbNameElement); Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(this.caseTextIndexName)); + indexNameElement.appendChild(doc.createTextNode(this.getCaseTextIndexName())); caseElement.appendChild(indexNameElement); - this.writeFile(); + this.writeFile(doc); } - private void writeFile() throws CaseMetadataException { - if (doc == null || caseName.equals("")) { + private void writeFile(Document doc) throws CaseMetadataException { + if (doc == null || getCaseName().equals("")) { throw new CaseMetadataException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.noCase.msg")); } @@ -372,7 +464,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(this.caseDirectory + File.separator + caseName + ".aut"); + File file = new File(this.getCaseDirectory() + File.separator + getCaseName() + ".aut"); // write the file try { @@ -387,4 +479,14 @@ public final class CaseMetadata { } } + /** + * When user wants to close the case. This method writes any changes to the + * XML case configuration file, closes it and the document handler, and + * clears all the local variables / fields. + * + */ + public void close() throws CaseMetadataException { + write(); // write any changes to xml + } + }