Update external results import code

This commit is contained in:
Richard Cordovano 2014-06-02 17:40:10 -04:00
parent 2c39db9591
commit 388dc636af
7 changed files with 319 additions and 327 deletions

View File

@ -0,0 +1,56 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
/**
* Encapsulates an error message and an associated exception, if any.
*/
final public class ErrorInfo {
private final String errorSource;
private final String message;
private final Exception exception;
public ErrorInfo(String errorSource, String message) {
this.errorSource = errorSource;
this.message = message;
this.exception = null;
}
public ErrorInfo(String errorSource, String message, Exception exception) {
this.errorSource = errorSource;
this.message = message;
this.exception = exception;
}
public String getErrroSource() {
return this.errorSource;
}
public String getMessage() {
return this.message;
}
public boolean hasException() {
return exception != null;
}
public Exception getException() {
return this.exception;
}
}

View File

@ -44,11 +44,11 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.externalresults.ExternalResults;
import org.sleuthkit.autopsy.externalresults.ExternalResultsImporter; import org.sleuthkit.autopsy.externalresults.ExternalResultsImporter;
import org.sleuthkit.autopsy.externalresults.ExternalResultsXML; import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule; import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
@ -111,7 +111,12 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
progressBar.progress(1); progressBar.progress(1);
// Import the results of the analysis. // Import the results of the analysis.
ExternalResultsImporter.importResultsFromXML(dataSource, resultsFilePath); ExternalResults results = new ExternalResultsXMLParser(dataSource, resultsFilePath).parse();
// RJCTODO: Get error messages
ExternalResultsImporter importer = new ExternalResultsImporter();
importer.importResults(results);
// RJCTODO: Get error messages
progressBar.progress(2); progressBar.progress(2);
} catch (TskCoreException | ParserConfigurationException | TransformerException | IOException ex) { } catch (TskCoreException | ParserConfigurationException | TransformerException | IOException ex) {
Logger logger = IngestServices.getInstance().getLogger(moduleName); Logger logger = IngestServices.getInstance().getLogger(moduleName);
@ -164,18 +169,18 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument(); Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement(ExternalResultsXML.ROOT_ELEM.toString()); Element rootElement = doc.createElement(ExternalResultsXMLParser.TagNames.ROOT_ELEM.toString());
doc.appendChild(rootElement); doc.appendChild(rootElement);
// Add an artifacts list element to the root element. // Add an artifacts list element to the root element.
Element artifactsListElement = doc.createElement(ExternalResultsXML.ARTIFACTS_LIST_ELEM.toString()); Element artifactsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACTS_LIST_ELEM.toString());
rootElement.appendChild(artifactsListElement); rootElement.appendChild(artifactsListElement);
// Add an artifact element to the artifacts list element. A standard // Add an artifact element to the artifacts list element. A standard
// artifact type is used as the required type attribute of this // artifact type is used as the required type attribute of this
// artifact element. // artifact element.
Element artifactElement = doc.createElement(ExternalResultsXML.ARTIFACT_ELEM.toString()); Element artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getLabel()); artifactElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getLabel());
artifactsListElement.appendChild(artifactElement); artifactsListElement.appendChild(artifactElement);
// Add an optional file element to the artifact element, and add a path // Add an optional file element to the artifact element, and add a path
@ -183,61 +188,61 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
// artifact is usually specified. If an artifact element has no file // artifact is usually specified. If an artifact element has no file
// element, the data source is used as the default source file for the // element, the data source is used as the default source file for the
// artifact. // artifact.
Element fileElement = doc.createElement(ExternalResultsXML.SOURCE_FILE_ELEM.toString()); Element fileElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_FILE_ELEM.toString());
artifactElement.appendChild(fileElement); artifactElement.appendChild(fileElement);
Element pathElement = doc.createElement(ExternalResultsXML.PATH_ELEM.toString()); Element pathElement = doc.createElement(ExternalResultsXMLParser.TagNames.PATH_ELEM.toString());
pathElement.setTextContent(dataSourcePath); pathElement.setTextContent(dataSourcePath);
fileElement.appendChild(pathElement); fileElement.appendChild(pathElement);
// Add an artifact attribute element to the artifact element. A standard // Add an artifact attribute element to the artifact element. A standard
// artifact attribute type is used as the required type XML attribute of // artifact attribute type is used as the required type XML attribute of
// the artifact attribute element. // the artifact attribute element.
Element artifactAttrElement = doc.createElement(ExternalResultsXML.ATTRIBUTE_ELEM.toString()); Element artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ATTRIBUTE_TYPE.TSK_SET_NAME.getLabel()); artifactAttrElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ATTRIBUTE_TYPE.TSK_SET_NAME.getLabel());
artifactElement.appendChild(artifactAttrElement); artifactElement.appendChild(artifactAttrElement);
// Add the required value element to the artifact attribute element, // Add the required value element to the artifact attribute element,
// with an optional type XML attribute of ExternalXML.VALUE_TYPE_TEXT, // with an optional type XML attribute of ExternalXML.VALUE_TYPE_TEXT,
// which is the default. // which is the default.
Element artifactAttributeValueElement = doc.createElement(ExternalResultsXML.VALUE_ELEM.toString()); Element artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
artifactAttributeValueElement.setTextContent("SampleInterestingFilesSet"); artifactAttributeValueElement.setTextContent("SampleInterestingFilesSet");
artifactAttrElement.appendChild(artifactAttributeValueElement); artifactAttrElement.appendChild(artifactAttributeValueElement);
// Add an optional source module element to the artifct attribute // Add an optional source module element to the artifct attribute
// element. // element.
Element artifactAttrSourceElement = doc.createElement(ExternalResultsXML.SOURCE_MODULE_ELEM.toString()); Element artifactAttrSourceElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
artifactAttrSourceElement.setTextContent(moduleName); artifactAttrSourceElement.setTextContent(moduleName);
artifactAttrElement.appendChild(artifactAttrSourceElement); artifactAttrElement.appendChild(artifactAttrSourceElement);
// Add an artifact element with a user-defined type. No file element is // Add an artifact element with a user-defined type. No file element is
// added to the artifact element, so the data source will be used as the // added to the artifact element, so the data source will be used as the
// default for the source file. // default for the source file.
artifactElement = doc.createElement(ExternalResultsXML.ARTIFACT_ELEM.toString()); artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), "SampleArtifactType"); artifactElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), "SampleArtifactType");
artifactsListElement.appendChild(artifactElement); artifactsListElement.appendChild(artifactElement);
// Add artifact attribute elements with user-defined types to the // Add artifact attribute elements with user-defined types to the
// artifact element, adding value elements of assorted types. // artifact element, adding value elements of assorted types.
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
artifactAttrElement = doc.createElement(ExternalResultsXML.ATTRIBUTE_ELEM.toString()); artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), "SampleArtifactAttributeType"); artifactAttrElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), "SampleArtifactAttributeType");
artifactElement.appendChild(artifactAttrElement); artifactElement.appendChild(artifactAttrElement);
artifactAttributeValueElement = doc.createElement(ExternalResultsXML.VALUE_ELEM.toString()); artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
switch (i) { switch (i) {
case 0: case 0:
artifactAttributeValueElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ExternalResultsXML.VALUE_TYPE_TEXT.toString()); artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.TagNames.VALUE_TYPE_TEXT.toString());
artifactAttributeValueElement.setTextContent("One"); artifactAttributeValueElement.setTextContent("One");
break; break;
case 1: case 1:
artifactAttributeValueElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ExternalResultsXML.VALUE_TYPE_INT32.toString()); artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.TagNames.VALUE_TYPE_INT32.toString());
artifactAttributeValueElement.setTextContent("2"); artifactAttributeValueElement.setTextContent("2");
break; break;
case 2: case 2:
artifactAttributeValueElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ExternalResultsXML.VALUE_TYPE_INT64.toString()); artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.TagNames.VALUE_TYPE_INT64.toString());
artifactAttributeValueElement.setTextContent("3"); artifactAttributeValueElement.setTextContent("3");
break; break;
case 3: case 3:
artifactAttributeValueElement.setAttribute(ExternalResultsXML.TYPE_ATTR.toString(), ExternalResultsXML.VALUE_TYPE_DOUBLE.toString()); artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.TagNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.TagNames.VALUE_TYPE_DOUBLE.toString());
artifactAttributeValueElement.setTextContent("4.0"); artifactAttributeValueElement.setTextContent("4.0");
break; break;
} }
@ -245,25 +250,25 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
} }
// Add a reports list element to the root element. // Add a reports list element to the root element.
Element reportsListElement = doc.createElement(ExternalResultsXML.REPORTS_LIST_ELEM.toString()); Element reportsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORTS_LIST_ELEM.toString());
rootElement.appendChild(reportsListElement); rootElement.appendChild(reportsListElement);
// Add a report element to the reports list element. // Add a report element to the reports list element.
Element reportElement = doc.createElement(ExternalResultsXML.REPORT_ELEM.toString()); Element reportElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_ELEM.toString());
reportsListElement.appendChild(reportElement); reportsListElement.appendChild(reportElement);
// Add the required display name element to the report element. // Add the required display name element to the report element.
Element reportDisplayNameElement = doc.createElement(ExternalResultsXML.DISPLAY_NAME_ELEM.toString()); Element reportDisplayNameElement = doc.createElement(ExternalResultsXMLParser.TagNames.DISPLAY_NAME_ELEM.toString());
reportDisplayNameElement.setTextContent("Sample Report"); reportDisplayNameElement.setTextContent("Sample Report");
reportElement.appendChild(reportDisplayNameElement); reportElement.appendChild(reportDisplayNameElement);
// Add the required local path element to the report element. // Add the required local path element to the report element.
Element reportPathElement = doc.createElement(ExternalResultsXML.LOCAL_PATH_ELEM.toString()); Element reportPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
reportPathElement.setTextContent(reportPath); reportPathElement.setTextContent(reportPath);
reportElement.appendChild(reportPathElement); reportElement.appendChild(reportPathElement);
// Add a derived files list element to the root element. // Add a derived files list element to the root element.
Element derivedFilesListElement = doc.createElement(ExternalResultsXML.DERIVED_FILES_LIST_ELEM.toString()); Element derivedFilesListElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILES_LIST_ELEM.toString());
rootElement.appendChild(derivedFilesListElement); rootElement.appendChild(derivedFilesListElement);
// Add derived file elements to the derived files list element. Each // Add derived file elements to the derived files list element. Each
@ -273,13 +278,13 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
// parent. // parent.
Element parentPathElement = null; Element parentPathElement = null;
for (String filePath : derivedFilePaths) { for (String filePath : derivedFilePaths) {
Element derivedFileElement = doc.createElement(ExternalResultsXML.DERIVED_FILE_ELEM.toString()); Element derivedFileElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILE_ELEM.toString());
derivedFilesListElement.appendChild(derivedFileElement); derivedFilesListElement.appendChild(derivedFileElement);
Element localPathElement = doc.createElement(ExternalResultsXML.LOCAL_PATH_ELEM.toString()); Element localPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
localPathElement.setTextContent(filePath); localPathElement.setTextContent(filePath);
derivedFileElement.appendChild(localPathElement); derivedFileElement.appendChild(localPathElement);
if (parentPathElement == null) { if (parentPathElement == null) {
parentPathElement = doc.createElement(ExternalResultsXML.PARENT_PATH_ELEM.toString()); parentPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.PARENT_PATH_ELEM.toString());
parentPathElement.setTextContent(dataSourcePath); parentPathElement.setTextContent(dataSourcePath);
derivedFileElement.appendChild(parentPathElement); derivedFileElement.appendChild(parentPathElement);
} }

View File

@ -23,10 +23,12 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestServices; import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent; import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
@ -36,232 +38,165 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Mechanism to import blackboard items, derived files, etc. It is decoupled * Uses a standard representation of results data (e.g., artifacts, derived
* from the actual parsing/interfacing with external data. * files, reports) to import results generated by a process external to Autopsy
* into Autopsy.
*/ */
public class ExternalResultsImporter { public final class ExternalResultsImporter {
private static final Logger logger = Logger.getLogger(ExternalResultsImporter.class.getName()); private static final Logger logger = Logger.getLogger(ExternalResultsImporter.class.getName());
private static final String EVENT_STRING = "External Results"; private final List<ErrorInfo> errors = new ArrayList<>();
/** /**
* Import results for a data source from an XML localFile (see * Import results generated by a process external to Autopsy into Autopsy.
* org.sleuthkit.autopsy.externalresults.autopsy_external_results.xsd).
* *
* @param dataSource A data source. * @param results A standard representation of results data (e.g.,
* @param resultsXmlPath Path to an XML localFile containing results (e.g., * artifacts, derived files, reports)from the data source.
* blackboard artifacts, derived files, reports) from the data source. * @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller to
* provide additional user feedback via the Autopsy user interface.
*/ */
public static void importResultsFromXML(Content dataSource, String resultsXmlPath) { // RJCTODO: Return error messages public List<ErrorInfo> importResults(ExternalResults results) {
ExternalResults results = new ExternalResultsXMLParser(dataSource, resultsXmlPath).parse(); // RJCTODO: Return error messages // Import files first, they may be artifactData sources.
// RJCTODO: Get external results, restore ExternalResults parser interface importDerivedFiles(results);
importDerivedFiles(results); // Import files first, they may be artifact sources. importArtifacts(results);
importArtifacts(dataSource, results);
importReports(results); importReports(results);
// return Collections.unmodifiableList(this.errors);
} }
private static void importDerivedFiles(ExternalResults results) { private void importDerivedFiles(ExternalResults results) {
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
for (ExternalResults.DerivedFile fileData : results.getDerivedFiles()) { for (ExternalResults.DerivedFile fileData : results.getDerivedFiles()) {
String filePath = Case.getCurrentCase().getCaseDirectory() + File.separator + fileData.getLocalPath();
try { try {
String localPath = fileData.getLocalPath(); File localFile = new File(filePath);
File localFile = new File(localPath); // RJCTODO: State/check ExternalResults contract that is not empty
if (!localFile.exists()) { if (!localFile.exists()) {
AbstractFile parentFile = findFileInDatabase(fileData.getParentPath()); AbstractFile parentFile = findFile(results.getDataSource(), fileData.getParentPath());
if (parentFile == null) { if (parentFile != null) {
String relativePath = getPathRelativeToCaseFolder(fileData.getLocalPath()); DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), fileData.getLocalPath(), localFile.length(),
DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), relativePath, localFile.length(), 0, 0, 0, 0, // Do not currently have file times for derived files from external processes.
0, 0, 0, 0, // Do not currently have localFile times for derived files, should they provide via XML? true, parentFile,
true, parentFile, "", "", "", ""); "", "", "", ""); // Not currently providing derivation info for derived files from external processes.
if (derivedFile != null) {
IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(derivedFile)); IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(derivedFile));
} else {
String errorMessage = String.format("Could not import derived file at %s, parent file %s not found", filePath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
} }
} else { } else {
// RJCTODO: parent file not in database String errorMessage = String.format("Could not import derived file at %s, file does not exist", filePath);
} ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
} else { this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
// RJCTODO: file missing
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, ex.getLocalizedMessage()); String errorMessage = String.format("Could not import derived file at %s, error querying/updating case database", filePath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
} }
} }
} }
/** private void importArtifacts(ExternalResults results) {
* Create and add new blackboard artifacts, attributes, and types SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
* for (ExternalResults.Artifact artifactData : results.getArtifacts()) {
* @param results
* @param dataSource
*/
private static void importArtifacts(Content dataSource, ExternalResults results) {
for (ExternalResults.Artifact art : results.getArtifacts()) {
try { try {
// Get the artifact type id if defined, or create a new // Add the artifact to the case database.
// user-defined artifact type. boolean artifactTypeIsUserDefined = false;
int artifactTypeId; int artifactTypeId = caseDb.getArtifactTypeIdIfExists(artifactData.getType());
BlackboardArtifact.ARTIFACT_TYPE stdArtType = isStandardArtifactType(art.getType()); if (artifactTypeId == -1) {
if (stdArtType != null) { artifactTypeId = caseDb.addArtifactType(artifactData.getType(), artifactData.getType());
artifactTypeId = stdArtType.getTypeID(); artifactTypeIsUserDefined = true;
} else {
artifactTypeId = Case.getCurrentCase().getSleuthkitCase().addArtifactType(art.getType(), art.getType());
} }
Content sourceFile = findFile(results.getDataSource(), artifactData.getSourceFilePath());
BlackboardArtifact artifact = sourceFile.newArtifact(artifactTypeId);
Collection<BlackboardAttribute> bbAttributes = new ArrayList<>(); // Add the artifact's attributes to the case database.
for (ExternalResults.ArtifactAttribute attr : art.getAttributes()) { Collection<BlackboardAttribute> attributes = new ArrayList<>();
int bbAttrTypeId; for (ExternalResults.ArtifactAttribute attributeData : artifactData.getAttributes()) {
BlackboardAttribute.ATTRIBUTE_TYPE stdAttrType = isStandardAttributeType(attr.getType()); int attributeTypeId = caseDb.getAttrTypeIdIfExists(attributeData.getType());
if (stdAttrType != null) { if (artifactTypeId == -1) {
bbAttrTypeId = stdAttrType.getTypeID(); artifactTypeId = caseDb.addArtifactType(attributeData.getType(), attributeData.getType());
} else {
// assume it's user defined RJCTODO fix
bbAttrTypeId = Case.getCurrentCase().getSleuthkitCase().addAttrType(attr.getType(), attr.getType());
} }
switch (attributeData.getValueType()) {
BlackboardAttribute bbAttr = null;
switch (attr.getValueType()) {
case "text": //NON-NLS case "text": //NON-NLS
bbAttr = new BlackboardAttribute(bbAttrTypeId, attr.getSourceModule(), attr.getValue()); attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), attributeData.getValue()));
break; break;
case "int32": //NON-NLS case "int32": //NON-NLS
int intValue = Integer.parseInt(attr.getValue()); int intValue = Integer.parseInt(attributeData.getValue());
bbAttr = new BlackboardAttribute(bbAttrTypeId, attr.getSourceModule(), intValue); attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), intValue));
break; break;
case "int64": //NON-NLS case "int64": //NON-NLS
long longValue = Long.parseLong(attr.getValue()); long longValue = Long.parseLong(attributeData.getValue());
bbAttr = new BlackboardAttribute(bbAttrTypeId, attr.getSourceModule(), longValue); attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), longValue));
break; break;
case "double": //NON-NLS case "double": //NON-NLS
double doubleValue = Double.parseDouble(attr.getValue()); double doubleValue = Double.parseDouble(attributeData.getValue());
bbAttr = new BlackboardAttribute(bbAttrTypeId, attr.getSourceModule(), doubleValue); attributes.add(new BlackboardAttribute(attributeTypeId, attributeData.getSourceModule(), doubleValue));
break; break;
default: default:
logger.log(Level.WARNING, "Ignoring invalid attribute value type {0}", attr.getValueType()); String errorMessage = String.format("Could not import %s attribute, value = %s, for %s artifact from %s, unrecognized attribute value type: %s",
attributeData.getType(), attributeData.getValue(),
artifactData.getType(), artifactData.getSourceFilePath(),
attributeData.getValueType());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
break; break;
} }
if (bbAttr != null) {
bbAttributes.add(bbAttr);
}
} }
artifact.addAttributes(attributes);
// Get associated localFile (if any) to use as the content obj to attach the artifact to if (!artifactTypeIsUserDefined) {
Content currContent = null; IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(this.getClass().getSimpleName(), BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId)));
if (art.getSourceFilePath().isEmpty()) {
currContent = findFileInDatabase(art.getSourceFilePath());
}
// If no associated localFile, use current data source itself
if (currContent == null) {
currContent = dataSource;
}
BlackboardArtifact bbArt = currContent.newArtifact(artifactTypeId);
bbArt.addAttributes(bbAttributes);
if (stdArtType != null) {
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent("", stdArtType)); //NON-NLS
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, ex.getLocalizedMessage()); String errorMessage = String.format("Could not import %s artifact from %s, error updating case database", artifactData.getType(), artifactData.getSourceFilePath());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
} }
} }
} }
private static void importReports(ExternalResults results) { private void importReports(ExternalResults results) {
for (ExternalResults.Report report : results.getReports()) { for (ExternalResults.Report report : results.getReports()) {
String reportPath = Case.getCurrentCase().getCaseDirectory() + File.separator + report.getLocalPath();
try { try {
String reportPath = report.getLocalPath();
File reportFile = new File(reportPath); File reportFile = new File(reportPath);
if (reportFile.exists()) { if (reportFile.exists()) {
// Try to get a relative local path Case.getCurrentCase().getSleuthkitCase().addReport(reportPath, report.getDisplayName());
String relPath = reportPath; } else {
Path pathTo = Paths.get(reportPath); String errorMessage = String.format("Could not import report at %s, file does not exist", reportPath);
if (pathTo.isAbsolute()) { ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
Path pathBase = Paths.get(Case.getCurrentCase().getCaseDirectory()); this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
try {
Path pathRelative = pathBase.relativize(pathTo);
relPath = pathRelative.toString();
} catch (IllegalArgumentException ex) {
logger.log(Level.WARNING, "Report file {0} path may be incorrect. The report record will still be added to the database.", reportPath);
}
}
if (!relPath.isEmpty()) {
Case.getCurrentCase().getSleuthkitCase().addReport(relPath, report.getDisplayName());
}
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, ex.getLocalizedMessage()); String errorMessage = String.format("Could not import report at %s, error updating case database", reportPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
} }
} }
} }
/** private AbstractFile findFile(Content dataSource, String filePath) throws TskCoreException {
* util function AbstractFile file = null;
* Path path = Paths.get(filePath);
* @param filePath full path including localFile or dir name
* @return AbstractFile
* @throws TskCoreException
*/
private static AbstractFile findFileInDatabase(String filePath) throws TskCoreException {
AbstractFile abstractFile = null;
String fileName = filePath;
String parentPath = "";
int charPos = filePath.lastIndexOf("/");
if (charPos >= 0) {
fileName = filePath.substring(charPos + 1);
parentPath = filePath.substring(0, charPos + 1);
}
String whereQuery = "name='" + fileName + "' AND parent_path='" + parentPath + "'"; //NON-NLS
List<AbstractFile> files = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(whereQuery);
if (files.size() > 0) {
abstractFile = files.get(0);
if (files.size() > 1) {
logger.log(Level.WARNING, "Ignoring extra files found for path {0}", filePath);
}
}
return abstractFile;
}
private static String getPathRelativeToCaseFolder(String localPath) {
String relativePath = "";
Path path = Paths.get(localPath);
if (path.isAbsolute()) { if (path.isAbsolute()) {
Path pathBase = Paths.get(Case.getCurrentCase().getCaseDirectory()); FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
try { List<AbstractFile> files = fileManager.openFiles(dataSource, filePath);
Path pathRelative = pathBase.relativize(path); if (files.size() > 0) {
relativePath = pathRelative.toString(); file = files.get(0);
} catch (IllegalArgumentException ex) { if (files.size() > 1) {
// RJCTODO: Fix this String errorMessage = String.format("Ambiguous file path: %s", filePath);
logger.log(Level.WARNING, "Report file {0} path may be incorrect. The report record will still be added to the database.", localPath); ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage));
}
} }
} else { } else {
// RJCTODO: Path is not absolute // RJCTODO: Need a look up that goes for relative path
} }
return relativePath; return file;
}
private static BlackboardArtifact.ARTIFACT_TYPE isStandardArtifactType(String artTypeStr) {
BlackboardArtifact.ARTIFACT_TYPE[] stdArts = BlackboardArtifact.ARTIFACT_TYPE.values();
for (BlackboardArtifact.ARTIFACT_TYPE art : stdArts) {
if (art.getLabel().equals(artTypeStr)) {
return art;
}
}
return null;
}
private static BlackboardAttribute.ATTRIBUTE_TYPE isStandardAttributeType(String attrTypeStr) {
BlackboardAttribute.ATTRIBUTE_TYPE[] stdAttrs = BlackboardAttribute.ATTRIBUTE_TYPE.values();
for (BlackboardAttribute.ATTRIBUTE_TYPE attr : stdAttrs) {
if (attr.getLabel().equals(attrTypeStr)) {
return attr;
}
}
return null;
} }
} }

View File

@ -19,11 +19,12 @@
package org.sleuthkit.autopsy.externalresults; package org.sleuthkit.autopsy.externalresults;
import java.util.List; import java.util.List;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
/** /**
* Interface for parsers that convert some representation of results data ( * Interface for parsers that convert some representation of results data (e.g.,
* e.g., artifacts, derived files, reports) generated by a process external to * artifacts, derived files, reports) generated by a process external to Autopsy
* Autopsy into a form ready for import into Autopsy. * into a form ready for import into Autopsy.
*/ */
public interface ExternalResultsParser { public interface ExternalResultsParser {
@ -32,15 +33,17 @@ public interface ExternalResultsParser {
* external to Autopsy and supplied to the parser via its constructor into a * external to Autopsy and supplied to the parser via its constructor into a
* form ready for import into Autopsy. * form ready for import into Autopsy.
* *
* @return Results data in a form ready for import into Autopsy. * @return External results data in a form ready for import into Autopsy.
*/ */
ExternalResults parse(); // RJCTODO: May need to add data source arg ExternalResults parse(); // RJCTODO: May need to add data source arg
/** /**
* Gets error messages describing any errors encountered while parsing the * Gets error information describing any errors encountered while parsing
* input results representation. * the input results representation.
* *
* @return A possibly empty collection of error message strings. * @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller to
* provide additional user feedback via the Autopsy user interface.
*/ */
List<String> getErrorMessages(); List<ErrorInfo> getErrorInfo();
} }

View File

@ -1,57 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.externalresults;
/**
* Tags for an external results XML file.
*/
public enum ExternalResultsXML {
ROOT_ELEM("autopsy_results"), //NON-NLS
ARTIFACTS_LIST_ELEM("artifacts"), //NON-NLS
ARTIFACT_ELEM("artifact"), //NON-NLS
SOURCE_FILE_ELEM("source_file"), //NON-NLS
PATH_ELEM("path"), //NON-NLS
ATTRIBUTE_ELEM("attribute"), //NON-NLS
VALUE_ELEM("value"), //NON-NLS
SOURCE_MODULE_ELEM("source_module"), //NON-NLS
REPORTS_LIST_ELEM("reports"), //NON-NLS
REPORT_ELEM("report"), //NON-NLS
DISPLAY_NAME_ELEM("display_name"), //NON-NLS
LOCAL_PATH_ELEM("local_path"), //NON-NLS
DERIVED_FILES_LIST_ELEM("derived_files"), //NON-NLS
DERIVED_FILE_ELEM("derived_file"), //NON-NLS
PARENT_PATH_ELEM("parent_path"), //NON-NLS
TYPE_ATTR("type"), //NON-NLS
NAME_ATTR("name"), //NON-NLS
VALUE_TYPE_TEXT("text"),
VALUE_TYPE_INT32("int32"),
VALUE_TYPE_INT64("int64"),
VALUE_TYPE_DOUBLE("double");
private final String text;
private ExternalResultsXML(final String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
}

View File

@ -18,9 +18,12 @@
*/ */
package org.sleuthkit.autopsy.externalresults; package org.sleuthkit.autopsy.externalresults;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -28,8 +31,8 @@ import org.w3c.dom.Element;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
/** /**
* Parses an XML representation of externally generated results (artifacts, * Parses an XML representation of of results data (e.g., artifacts, derived
* derived files, and reports). * files, reports) generated by a process external to Autopsy into Autopsy.
*/ */
public final class ExternalResultsXMLParser implements ExternalResultsParser { public final class ExternalResultsXMLParser implements ExternalResultsParser {
@ -37,13 +40,52 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
private static final String XSD_FILE = "autopsy_external_results.xsd"; //NON-NLS private static final String XSD_FILE = "autopsy_external_results.xsd"; //NON-NLS
private final String resultsFilePath; private final String resultsFilePath;
private final ExternalResults externalResults; private final ExternalResults externalResults;
private final List<ErrorInfo> errors = new ArrayList<>();
/**
* Tags for an external results XML file.
*/
public enum TagNames {
ROOT_ELEM("autopsy_results"), //NON-NLS
ARTIFACTS_LIST_ELEM("artifacts"), //NON-NLS
ARTIFACT_ELEM("artifact"), //NON-NLS
SOURCE_FILE_ELEM("source_file"), //NON-NLS
PATH_ELEM("path"), //NON-NLS
ATTRIBUTE_ELEM("attribute"), //NON-NLS
VALUE_ELEM("value"), //NON-NLS
SOURCE_MODULE_ELEM("source_module"), //NON-NLS
REPORTS_LIST_ELEM("reports"), //NON-NLS
REPORT_ELEM("report"), //NON-NLS
DISPLAY_NAME_ELEM("display_name"), //NON-NLS
LOCAL_PATH_ELEM("local_path"), //NON-NLS
DERIVED_FILES_LIST_ELEM("derived_files"), //NON-NLS
DERIVED_FILE_ELEM("derived_file"), //NON-NLS
PARENT_PATH_ELEM("parent_path"), //NON-NLS
TYPE_ATTR("type"), //NON-NLS
NAME_ATTR("name"), //NON-NLS
VALUE_TYPE_TEXT("text"),
VALUE_TYPE_INT32("int32"),
VALUE_TYPE_INT64("int64"),
VALUE_TYPE_DOUBLE("double");
private final String text;
private TagNames(final String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
}
/** /**
* Constructor. * Constructor.
* *
* @param importFilePath Full path of the results file to be parsed. * @param importFilePath Full path of the results file to be parsed.
*/ */
ExternalResultsXMLParser(Content dataSource, String resultsFilePath) { public ExternalResultsXMLParser(Content dataSource, String resultsFilePath) {
this.resultsFilePath = resultsFilePath; this.resultsFilePath = resultsFilePath;
externalResults = new ExternalResults(dataSource); externalResults = new ExternalResults(dataSource);
} }
@ -59,38 +101,57 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE); final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE);
if (doc != null) { if (doc != null) {
final Element rootElem = doc.getDocumentElement(); final Element rootElem = doc.getDocumentElement();
if (rootElem != null && rootElem.getNodeName().equals(ExternalResultsXML.ROOT_ELEM.toString())) { if (rootElem != null && rootElem.getNodeName().equals(TagNames.ROOT_ELEM.toString())) {
parseDerivedFiles(rootElem);
parseArtifacts(rootElem); parseArtifacts(rootElem);
parseReports(rootElem); parseReports(rootElem);
parseDerivedFiles(rootElem);
} else { } else {
logger.log(Level.SEVERE, "Did not find {0} root element of {2}", new Object[]{ String errorMessage = String.format("Did not find %s root element of %s", TagNames.ROOT_ELEM.toString(), this.resultsFilePath);
ExternalResultsXML.ROOT_ELEM.toString(), this.resultsFilePath}); //NON-NLS recordError(errorMessage);
} }
} }
} catch (Exception e) { } catch (Exception ex) {
logger.log(Level.SEVERE, "Error parsing " + this.resultsFilePath, e); //NON-NLS String errorMessage = String.format("Error parsing %s", this.resultsFilePath);
recordError(errorMessage, ex);
} }
return externalResults; return externalResults;
} }
@Override @Override
public List<String> getErrorMessages() { public List<ErrorInfo> getErrorInfo() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. return Collections.unmodifiableList(this.errors);
}
private void parseDerivedFiles(Element rootElement) {
NodeList derivedFilesListNodes = rootElement.getElementsByTagName(TagNames.DERIVED_FILES_LIST_ELEM.toString());
for (int i = 0; i < derivedFilesListNodes.getLength(); ++i) {
Element derivedFilesListElem = (Element) derivedFilesListNodes.item(i);
NodeList derivedFileNodes = derivedFilesListElem.getElementsByTagName(TagNames.DERIVED_FILE_ELEM.toString());
for (int j = 0; j < derivedFileNodes.getLength(); ++j) {
Element derivedFileElem = (Element) derivedFileNodes.item(j);
String path = getChildElementContent(derivedFileElem, TagNames.LOCAL_PATH_ELEM.toString());
if (path.isEmpty()) {
continue;
}
String parentPath = getChildElementContent((Element) derivedFileNodes.item(j), TagNames.PARENT_PATH_ELEM.toString());
if (parentPath.isEmpty()) {
continue;
}
externalResults.addDerivedFile(path, parentPath);
}
}
} }
private void parseArtifacts(final Element root) { private void parseArtifacts(final Element root) {
NodeList artifactsListNodes = root.getElementsByTagName(ExternalResultsXML.ARTIFACTS_LIST_ELEM.toString()); NodeList artifactsListNodes = root.getElementsByTagName(TagNames.ARTIFACTS_LIST_ELEM.toString());
for (int i = 0; i < artifactsListNodes.getLength(); ++i) { for (int i = 0; i < artifactsListNodes.getLength(); ++i) {
Element artifactsListElem = (Element) artifactsListNodes.item(i); Element artifactsListElem = (Element) artifactsListNodes.item(i);
NodeList artifactNodes = artifactsListElem.getElementsByTagName(ExternalResultsXML.ARTIFACT_ELEM.toString()); NodeList artifactNodes = artifactsListElem.getElementsByTagName(TagNames.ARTIFACT_ELEM.toString());
for (int j = 0; j < artifactNodes.getLength(); ++j) { for (int j = 0; j < artifactNodes.getLength(); ++j) {
Element artifactElem = (Element) artifactNodes.item(j); Element artifactElem = (Element) artifactNodes.item(j);
final String type = getElementAttributeValue(artifactElem, ExternalResultsXML.TYPE_ATTR.toString()); final String type = getElementAttributeValue(artifactElem, TagNames.TYPE_ATTR.toString());
if (!type.isEmpty()) { if (!type.isEmpty()) {
Element sourceFileElem = getChildElement(artifactElem, ExternalResultsXML.SOURCE_FILE_ELEM.toString()); final String sourceFilePath = this.getChildElementContent((Element) artifactElem, TagNames.PATH_ELEM.toString());
if (sourceFileElem != null) {
final String sourceFilePath = this.getChildElementContent((Element) sourceFileElem, ExternalResultsXML.PATH_ELEM.toString());
if (!sourceFilePath.isEmpty()) { if (!sourceFilePath.isEmpty()) {
ExternalResults.Artifact artifact = externalResults.addArtifact(type, sourceFilePath); ExternalResults.Artifact artifact = externalResults.addArtifact(type, sourceFilePath);
parseArtifactAttributes(artifactElem, artifact); parseArtifactAttributes(artifactElem, artifact);
@ -99,42 +160,41 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
} }
} }
} }
}
private void parseArtifactAttributes(final Element artifactElem, ExternalResults.Artifact artifact) { private void parseArtifactAttributes(final Element artifactElem, ExternalResults.Artifact artifact) {
NodeList attributeNodesList = artifactElem.getElementsByTagName(ExternalResultsXML.ATTRIBUTE_ELEM.toString()); NodeList attributeNodesList = artifactElem.getElementsByTagName(TagNames.ATTRIBUTE_ELEM.toString());
for (int i = 0; i < attributeNodesList.getLength(); ++i) { for (int i = 0; i < attributeNodesList.getLength(); ++i) {
// Get the type of the artifact attribute. // Get the type of the artifact attribute.
Element attributeElem = (Element) attributeNodesList.item(i); Element attributeElem = (Element) attributeNodesList.item(i);
final String type = getElementAttributeValue(attributeElem, ExternalResultsXML.TYPE_ATTR.toString()); final String type = getElementAttributeValue(attributeElem, TagNames.TYPE_ATTR.toString());
if (type.isEmpty()) { if (type.isEmpty()) {
continue; continue;
} }
// Get the value of the artifact attribute. // Get the value of the artifact attribute.
Element valueElem = this.getChildElement(attributeElem, ExternalResultsXML.VALUE_ELEM.toString()); Element valueElem = this.getChildElement(attributeElem, TagNames.VALUE_ELEM.toString());
if (valueElem == null) { if (valueElem == null) {
continue; continue;
} }
final String value = valueElem.getTextContent(); final String value = valueElem.getTextContent();
if (value.isEmpty()) { if (value.isEmpty()) {
logger.log(Level.WARNING, "Found {0} element that has no content in {1}", new Object[]{ String errorMessage = String.format("Found %s element that has no content in %s",
ExternalResultsXML.VALUE_ELEM.toString(), this.resultsFilePath}); TagNames.VALUE_ELEM.toString(), this.resultsFilePath);
recordError(errorMessage);
continue; continue;
} }
// Get the value type. // Get the value type.
String valueType = valueElem.getAttribute(ExternalResultsXML.TYPE_ATTR.toString()); String valueType = valueElem.getAttribute(TagNames.TYPE_ATTR.toString());
if (valueType.isEmpty()) { if (valueType.isEmpty()) {
valueType = ExternalResultsXML.VALUE_TYPE_TEXT.toString(); valueType = TagNames.VALUE_TYPE_TEXT.toString();
} }
// Get the source module for the artifact attribute. // Get the source module for the artifact attribute.
String sourceModule = ""; String sourceModule = "";
NodeList sourceModuleNodes = attributeElem.getElementsByTagName(ExternalResultsXML.SOURCE_MODULE_ELEM.toString()); NodeList sourceModuleNodes = attributeElem.getElementsByTagName(TagNames.SOURCE_MODULE_ELEM.toString());
if (sourceModuleNodes.getLength() > 0) { if (sourceModuleNodes.getLength() > 0) {
if (sourceModuleNodes.getLength() > 1) { if (sourceModuleNodes.getLength() > 1) {
logger.log(Level.WARNING, "Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence", new Object[]{ String errorMessage = String.format("Found multiple %s child elements for %s element in %s, ignoring all but first occurrence",
ExternalResultsXML.SOURCE_MODULE_ELEM.toString(), TagNames.SOURCE_MODULE_ELEM.toString(), attributeElem.getTagName(), this.resultsFilePath);
attributeElem.getTagName(), recordError(errorMessage);
this.resultsFilePath}); // NON-NLS
} }
Element srcModuleElem = (Element) sourceModuleNodes.item(0); Element srcModuleElem = (Element) sourceModuleNodes.item(0);
sourceModule = srcModuleElem.getTextContent(); sourceModule = srcModuleElem.getTextContent();
@ -145,17 +205,17 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
} }
private void parseReports(Element root) { private void parseReports(Element root) {
NodeList reportsListNodes = root.getElementsByTagName(ExternalResultsXML.REPORTS_LIST_ELEM.toString()); NodeList reportsListNodes = root.getElementsByTagName(TagNames.REPORTS_LIST_ELEM.toString());
for (int i = 0; i < reportsListNodes.getLength(); ++i) { for (int i = 0; i < reportsListNodes.getLength(); ++i) {
Element reportsListElem = (Element) reportsListNodes.item(i); Element reportsListElem = (Element) reportsListNodes.item(i);
NodeList reportNodes = reportsListElem.getElementsByTagName(ExternalResultsXML.REPORT_ELEM.toString()); NodeList reportNodes = reportsListElem.getElementsByTagName(TagNames.REPORT_ELEM.toString());
for (int j = 0; j < reportNodes.getLength(); ++j) { for (int j = 0; j < reportNodes.getLength(); ++j) {
Element reportElem = (Element) reportNodes.item(j); Element reportElem = (Element) reportNodes.item(j);
String displayName = getChildElementContent(reportElem, ExternalResultsXML.DISPLAY_NAME_ELEM.toString()); String displayName = getChildElementContent(reportElem, TagNames.DISPLAY_NAME_ELEM.toString());
if (displayName.isEmpty()) { if (displayName.isEmpty()) {
continue; continue;
} }
String path = getChildElementContent(reportElem, ExternalResultsXML.LOCAL_PATH_ELEM.toString()); String path = getChildElementContent(reportElem, TagNames.LOCAL_PATH_ELEM.toString());
if (displayName.isEmpty()) { if (displayName.isEmpty()) {
continue; continue;
} }
@ -164,32 +224,12 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
} }
} }
private void parseDerivedFiles(Element rootElement) {
NodeList derivedFilesListNodes = rootElement.getElementsByTagName(ExternalResultsXML.DERIVED_FILES_LIST_ELEM.toString());
for (int i = 0; i < derivedFilesListNodes.getLength(); ++i) {
Element derivedFilesListElem = (Element) derivedFilesListNodes.item(i);
NodeList derivedFileNodes = derivedFilesListElem.getElementsByTagName(ExternalResultsXML.DERIVED_FILE_ELEM.toString());
for (int j = 0; j < derivedFileNodes.getLength(); ++j) {
Element derivedFileElem = (Element) derivedFileNodes.item(j);
String path = getChildElementContent(derivedFileElem, ExternalResultsXML.LOCAL_PATH_ELEM.toString());
if (path.isEmpty()) {
continue;
}
String parentPath = getChildElementContent((Element) derivedFileNodes.item(j), ExternalResultsXML.PARENT_PATH_ELEM.toString());
if (parentPath.isEmpty()) {
continue;
}
externalResults.addDerivedFile(path, parentPath);
}
}
}
private Element getChildElement(Element parentElement, String childElementTagName) { private Element getChildElement(Element parentElement, String childElementTagName) {
Element childElem = null; Element childElem = null;
NodeList childNodes = parentElement.getElementsByTagName(childElementTagName); NodeList childNodes = parentElement.getElementsByTagName(childElementTagName);
if (childNodes.getLength() > 0) { if (childNodes.getLength() > 0) {
if (childNodes.getLength() > 1) { if (childNodes.getLength() > 1) {
logger.log(Level.WARNING, "Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence", new Object[]{ logger.log(Level.SEVERE, "Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence", new Object[]{
childElementTagName, childElementTagName,
parentElement.getTagName(), parentElement.getTagName(),
this.resultsFilePath}); // NON-NLS this.resultsFilePath}); // NON-NLS
@ -201,7 +241,7 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
private String getElementAttributeValue(Element element, String attributeName) { private String getElementAttributeValue(Element element, String attributeName) {
final String attributeValue = element.getAttribute(attributeName); final String attributeValue = element.getAttribute(attributeName);
if (attributeValue.isEmpty()) { if (attributeValue.isEmpty()) {
logger.log(Level.WARNING, "Found {0} element missing {1} attribute in {2}", new Object[]{ logger.log(Level.SEVERE, "Found {0} element missing {1} attribute in {2}", new Object[]{
element.getTagName(), element.getTagName(),
attributeName, attributeName,
this.resultsFilePath}); this.resultsFilePath});
@ -214,7 +254,7 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
NodeList childNodes = parentElement.getElementsByTagName(childElementTagName); NodeList childNodes = parentElement.getElementsByTagName(childElementTagName);
if (childNodes.getLength() > 0) { if (childNodes.getLength() > 0) {
if (childNodes.getLength() > 1) { if (childNodes.getLength() > 1) {
logger.log(Level.WARNING, "Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence", new Object[]{ logger.log(Level.SEVERE, "Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence", new Object[]{
childElementTagName, childElementTagName,
parentElement.getTagName(), parentElement.getTagName(),
this.resultsFilePath}); // NON-NLS this.resultsFilePath}); // NON-NLS
@ -222,17 +262,27 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
Element childElement = (Element) childNodes.item(0); Element childElement = (Element) childNodes.item(0);
content = childElement.getTextContent(); content = childElement.getTextContent();
if (content.isEmpty()) { if (content.isEmpty()) {
logger.log(Level.WARNING, "Found {0} element with {1} child element that has no content in {2}", new Object[]{ logger.log(Level.SEVERE, "Found {0} element with {1} child element that has no content in {2}", new Object[]{
parentElement.getTagName(), parentElement.getTagName(),
childElementTagName, childElementTagName,
this.resultsFilePath}); // NON-NLS this.resultsFilePath}); // NON-NLS
} }
} else { } else {
logger.log(Level.WARNING, "Found {0} element missing {1} child element in {2}", new Object[]{ logger.log(Level.SEVERE, "Found {0} element missing {1} child element in {2}", new Object[]{
parentElement.getTagName(), parentElement.getTagName(),
childElementTagName, childElementTagName,
this.resultsFilePath}); // NON-NLS this.resultsFilePath}); // NON-NLS
} }
return content; return content;
} }
private void recordError(String errorMessage) {
this.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage));
}
private void recordError(String errorMessage, Exception ex) {
this.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage, ex));
}
} }