Improved layout and styling of ingest messages to have style sheets and consistent look and feel

This commit is contained in:
Brian Carrier 2013-08-08 18:02:18 -04:00
parent b40291038a
commit 36c37e52ff
6 changed files with 81 additions and 65 deletions

View File

@ -774,7 +774,7 @@ public class IngestManager {
public String toHtmlString() {
StringBuilder sb = new StringBuilder();
sb.append("<html>");
sb.append("<html><body>");
sb.append("Ingest time: ").append(getTotalTimeString()).append("<br />");
sb.append("Total errors: ").append(errorsTotal).append("<br />");
@ -788,7 +788,7 @@ public class IngestManager {
}
* */
sb.append("</html>");
sb.append("</body></html>");
return sb.toString();
}

View File

@ -171,14 +171,14 @@ public class IngestMessage {
* @param messageType message type
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null.
* @return
*/
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String details) {
public static IngestMessage createMessage(long ID, MessageType messageType, IngestModuleAbstract source, String subject, String detailsHtml) {
if (messageType == null || source == null || subject == null) {
throw new IllegalArgumentException("message type, source and subject cannot be null");
}
return new IngestMessage(ID, messageType, source, subject, details, null);
return new IngestMessage(ID, messageType, source, subject, detailsHtml, null);
}
/**
@ -199,14 +199,14 @@ public class IngestMessage {
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null
* @return
*/
public static IngestMessage createErrorMessage(long ID, IngestModuleAbstract source, String subject, String details) {
public static IngestMessage createErrorMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml) {
if (source == null || subject == null) {
throw new IllegalArgumentException("source and subject cannot be null");
}
return new IngestMessage(ID, MessageType.ERROR, source, subject, details, null);
return new IngestMessage(ID, MessageType.ERROR, source, subject, detailsHtml, null);
}
/**
@ -214,14 +214,14 @@ public class IngestMessage {
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating module
* @param subject message subject to be displayed
* @param details message details to be displayed, or null
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null
* @return
*/
public static IngestMessage createWarningMessage(long ID, IngestModuleAbstract source, String subject, String details) {
public static IngestMessage createWarningMessage(long ID, IngestModuleAbstract source, String subject, String detailsHtml) {
if (source == null || subject == null) {
throw new IllegalArgumentException("source and subject cannot be null");
}
return new IngestMessage(ID, MessageType.WARNING, source, subject, details, null);
return new IngestMessage(ID, MessageType.WARNING, source, subject, detailsHtml, null);
}
/**
@ -229,7 +229,7 @@ public class IngestMessage {
* @param ID ID of the message, unique in the context of module that generated it
* @param source originating module
* @param subject message subject to be displayed
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data.
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null.
* @param uniqueKey Key used to group similar messages together. Shoudl be unique to the analysis. For example, hits for the same keyword in a keyword search would use the keyword as this unique value so that they can be grouped.
* @param data blackboard artifact associated with the message, the same as fired in ModuleDataEvent by the module
* @return
@ -246,6 +246,9 @@ public class IngestMessage {
/**
* Used by IngestMager to post status messages.
* @param subject message subject to be displayed
* @param detailsHtml html formatted detailed message (without leading and closing &lt;html&gt; tags), for instance, a human-readable representation of the data. Or null.
*/
static IngestMessage createManagerMessage(String subject, String detailsHtml) {
return new IngestMessage(++managerMessageId, MessageType.INFO, null, subject, detailsHtml, null);

View File

@ -24,6 +24,8 @@ import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JMenuItem;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
@ -51,6 +53,18 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel {
messageDetailsPane.setContentType("text/html");
viewArtifactButton.setEnabled(false);
viewContentButton.setEnabled(false);
HTMLEditorKit kit = new HTMLEditorKit();
messageDetailsPane.setEditorKit(kit);
StyleSheet styleSheet = kit.getStyleSheet();
/* I tried to define the font-size only on body to have it inherit,
* it didn't work in all cases. */
styleSheet.addRule("body {font-family:Arial;font-size:10pt;}");
styleSheet.addRule("p {font-family:Arial;font-size:10pt;}");
styleSheet.addRule("li {font-family:Arial;font-size:10pt;}");
styleSheet.addRule("table {table-layout:fixed;}");
styleSheet.addRule("td {white-space:pre-wrap;overflow:hidden;}");
styleSheet.addRule("th {font-weight:bold;}");
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
v.addOnFinishedListener(new PropertyChangeListener() {
@ -236,22 +250,24 @@ class IngestMessageDetailsPanel extends javax.swing.JPanel {
messageDetailsPane.setCursor(null);
}
/**
* Display the details of a given message
* @param rowNumber index to the message to display
*/
void showDetails(int rowNumber) {
final IngestMessageGroup messageGroup = mainPanel.getMessagePanel().getMessageGroup(rowNumber);
if (messageGroup != null) {
String details = messageGroup.getDetails();
if (details != null) {
StringBuilder b = new StringBuilder();
b.append("<html>");
b.append("<head>");
b.append("<style type='text/css'>");
b.append("table {table-layout:fixed;}");
b.append("td {font-family:Arial;font-size:10pt;white-space:pre-wrap;overflow:hidden;}");
b.append("th {font-family:Arial;font-size:10pt;font-weight:bold;}");
b.append("p {font-family:Arial;font-size:10pt;}");
b.append("</style>");
b.append("</head>");
b.append(details).append("</html>");
if (details.startsWith("<html><body>") == false) {
b.append("<html><body>");
b.append(details);
b.append("</body></html>");
}
else {
b.append(details);
}
this.messageDetailsPane.setText(b.toString());
} else {
this.messageDetailsPane.setText("");

View File

@ -130,25 +130,19 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
//details
detailsSb.append("<table border='0' cellpadding='4' width='280'>");
detailsSb.append("<tr>");
detailsSb.append("<th>Number of notable files found:</th>");
detailsSb.append("<td>").append(knownBadCount).append("</td>");
detailsSb.append("</tr>");
detailsSb.append("<tr><td>Known bads found:</td>");
detailsSb.append("<td>").append(knownBadCount).append("</td></tr>");
detailsSb.append("<tr>");
detailsSb.append("<th>Notable databases used:</th>");
detailsSb.append("<td>Calc Time: ").append(calctime).append(" Lookup Time: ").append(lookuptime).append("</td>");
detailsSb.append("</tr>");
detailsSb.append("<tr><td>Total Calculation Time</td><td>").append(calctime).append("</td></tr>\n");
detailsSb.append("<tr><td>Total Lookup Time</td><td>").append(lookuptime).append("</td></tr>\n");
detailsSb.append("</table>");
detailsSb.append("<p>Databases Used:</p>\n<ul>");
for (HashDb db : knownBadSets.values()) {
detailsSb.append("<tr><th>");
detailsSb.append(db.getName());
detailsSb.append("</th><td>");
detailsSb.append(db.getDatabasePaths().get(0)); // TODO: support multiple database paths
detailsSb.append("</td></tr>");
detailsSb.append("<li>").append(db.getName()).append("</li>\n");
}
detailsSb.append("</table>");
detailsSb.append("</ul>");
services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString()));
clearHashDatabaseHandles();
}

View File

@ -135,8 +135,10 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
private enum IngestStatus {
INGESTED, EXTRACTED_INGESTED, SKIPPED, INGESTED_META
TEXT_INGESTED, /// Text was extracted by knowing file type and text_ingested
STRINGS_INGESTED, ///< Strings were extracted from file
SKIPPED, ///< File was skipped for whatever reason
METADATA_INGESTED ///< No content, so we just text_ingested metadata
};
private Map<Long, IngestStatus> ingestStatus;
@ -238,7 +240,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
//log number of files / chunks in index
//signal a potential change in number of indexed files
//signal a potential change in number of text_ingested files
try {
final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
final int numIndexedChunks = KeywordSearch.getServer().queryNumIndexedChunks();
@ -350,7 +352,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
if (!server.isRunning()) {
String msg = "Keyword search server was not properly initialized, cannot run keyword search ingest. ";
logger.log(Level.SEVERE, msg);
String details = msg + "Please try stopping old java Solr process (if it exists) and restart the application.";
String details = msg + "<br />Please try stopping old java Solr process (if it exists) and restart the application.";
services.postMessage(IngestMessage.createErrorMessage(++messageID, instance, msg, details));
return;
@ -359,7 +361,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
logger.log(Level.WARNING, "Error checking if Solr server is running while initializing ingest", ex);
//this means Solr is not properly initialized
String msg = "Keyword search server was not properly initialized, cannot run keyword search ingest. ";
String details = msg + "Please try stopping old java Solr process (if it exists) and restart the application.";
String details = msg + "<br />Please try stopping old java Solr process (if it exists) and restart the application.";
services.postMessage(IngestMessage.createErrorMessage(++messageID, instance, msg, details));
return;
}
@ -485,29 +487,29 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
logger.log(Level.INFO, "Commiting index");
ingester.commit();
logger.log(Level.INFO, "Index comitted");
//signal a potential change in number of indexed files
//signal a potential change in number of text_ingested files
indexChangeNotify();
}
}
/**
* Posts inbox message with summary of indexed files
* Posts inbox message with summary of text_ingested files
*/
private void postIndexSummary() {
int indexed = 0;
int indexed_meta = 0;
int indexed_extr = 0;
int text_ingested = 0;
int metadata_ingested = 0;
int strings_ingested = 0;
int skipped = 0;
for (IngestStatus s : ingestStatus.values()) {
switch (s) {
case INGESTED:
++indexed;
case TEXT_INGESTED:
++text_ingested;
break;
case INGESTED_META:
++indexed_meta;
case METADATA_INGESTED:
++metadata_ingested;
break;
case EXTRACTED_INGESTED:
++indexed_extr;
case STRINGS_INGESTED:
++strings_ingested;
break;
case SKIPPED:
++skipped;
@ -518,20 +520,21 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
}
StringBuilder msg = new StringBuilder();
msg.append("Indexed files: ").append(indexed).append("<br />Indexed strings: ").append(indexed_extr);
msg.append("<br />Indexed meta-data only: ").append(indexed_meta).append("<br />");
msg.append("<br />Skipped files: ").append(skipped).append("<br />");
msg.append("<table border=0><tr><td>Files with known types</td><td>").append(text_ingested).append("</td></tr>");
msg.append("<tr><td>Files with general strings extracted</td><td>").append(strings_ingested).append("</td></tr>");
msg.append("<tr><td>Metadata only was indexed</td><td>").append(metadata_ingested).append("</td></tr>");
msg.append("<tr><td>Skipped files</td><td>").append(skipped).append("</td></tr>");
msg.append("</table>");
String indexStats = msg.toString();
logger.log(Level.INFO, "Keyword Indexing Completed: " + indexStats);
services.postMessage(IngestMessage.createMessage(++messageID, MessageType.INFO, this, "Keyword Indexing Results", indexStats));
}
/**
* Helper method to notify listeners on index update
*/
private void indexChangeNotify() {
//signal a potential change in number of indexed files
//signal a potential change in number of text_ingested files
try {
final int numIndexedFiles = KeywordSearch.getServer().queryNumIndexedFiles();
KeywordSearch.fireNumIndexedFilesChange(null, new Integer(numIndexedFiles));
@ -662,7 +665,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
* @param aFile file to extract strings from, divide into chunks and
* index
* @param detectedFormat mime-type detected, or null if none detected
* @return true if the file was indexed, false otherwise
* @return true if the file was text_ingested, false otherwise
* @throws IngesterException exception thrown if indexing failed
*/
private boolean extractTextAndIndex(AbstractFile aFile, String detectedFormat) throws IngesterException {
@ -693,12 +696,12 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
*
* @param aFile file to extract strings from, divide into chunks and
* index
* @return true if the file was indexed, false otherwise
* @return true if the file was text_ingested, false otherwise
*/
private boolean extractStringsAndIndex(AbstractFile aFile) {
try {
if (stringExtractor.index(aFile)) {
ingestStatus.put(aFile.getId(), IngestStatus.EXTRACTED_INGESTED);
ingestStatus.put(aFile.getId(), IngestStatus.STRINGS_INGESTED);
return true;
} else {
logger.log(Level.WARNING, "Failed to extract strings and ingest, file '" + aFile.getName() + "' (id: " + aFile.getId() + ").");
@ -735,7 +738,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
* Adds the file to the index. Detects file type, calls extractors, etc.
*
* @param aFile File to analyze
* @param indexContent False if only metadata should be indexed. True if
* @param indexContent False if only metadata should be text_ingested. True if
* content and metadata should be index.
*/
private void indexFile(AbstractFile aFile, boolean indexContent) {
@ -756,7 +759,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
if ((indexContent == false || aFile.isDir() || size == 0)) {
try {
ingester.ingest(aFile, false); //meta-data only
ingestStatus.put(aFile.getId(), IngestStatus.INGESTED_META);
ingestStatus.put(aFile.getId(), IngestStatus.METADATA_INGESTED);
} catch (IngesterException ex) {
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED);
logger.log(Level.WARNING, "Unable to index meta-data for file: " + aFile.getId(), ex);
@ -802,7 +805,7 @@ public final class KeywordSearchIngestModule extends IngestModuleAbstractFile {
logger.log(Level.WARNING, "Failed to extract text and ingest, file '" + aFile.getName() + "' (id: " + aFile.getId() + ").");
ingestStatus.put(aFile.getId(), IngestStatus.SKIPPED);
} else {
ingestStatus.put(aFile.getId(), IngestStatus.INGESTED);
ingestStatus.put(aFile.getId(), IngestStatus.TEXT_INGESTED);
wasTextAdded = true;
}

View File

@ -85,7 +85,7 @@ public final class RAImageIngestModule extends IngestModuleDataSource {
StringBuilder errorMessage = new StringBuilder();
String errorMsgSubject;
if (!errors.isEmpty()) {
errorMessage.append("Errors encountered during analysis: <ul>\n");
errorMessage.append("<p>Errors encountered during analysis: <ul>\n");
for (String msg : errors) {
errorMessage.append("<li>").append(msg).append("</li>\n");
}
@ -97,7 +97,7 @@ public final class RAImageIngestModule extends IngestModuleDataSource {
errorMsgSubject = errors.size() + " errors found";
}
} else {
errorMessage.append("No errors encountered.");
errorMessage.append("<p>No errors encountered.</p>");
errorMsgSubject = "No errors reported";
}
final IngestMessage msg = IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Finished " + dataSource.getName()+ " - " + errorMsgSubject, errorMessage.toString());