From 69e3efe160b0677c92af63fa915b139af42ad57b Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 27 Jan 2012 15:21:22 -0500 Subject: [PATCH 01/10] Show dialog with summary when ingest complete --- .../autopsy/ingest/IngestManager.java | 50 +++++++++++++++++-- .../autopsy/ingest/IngestMessage.java | 9 +++- .../autopsy/ingest/IngestMessagePanel.form | 1 - .../autopsy/ingest/IngestMessagePanel.java | 8 ++- .../autopsy/ingest/IngestTopComponent.form | 2 +- .../autopsy/ingest/IngestTopComponent.java | 3 -- 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 6167ff6796..e99cbd09fb 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -33,12 +33,14 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.util.Cancellable; import org.openide.util.Lookup; +import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.Image; @@ -153,6 +155,13 @@ public class IngestManager { */ public synchronized void postMessage(final IngestMessage message) { + if (stats != null) { + //record the error for stats, if stats are running + if (message.getMessageType() == MessageType.ERROR) { + stats.addError(message.getSource()); + } + } + SwingUtilities.invokeLater(new Runnable() { @Override @@ -476,6 +485,28 @@ public class IngestManager { return sb.toString(); } + public String toHtmlString() { + StringBuilder sb = new StringBuilder(); + sb.append(""); + if (startTime != null) { + sb.append("Start time: ").append(dateFormatter.format(startTime)).append("
"); + } + if (endTime != null) { + sb.append("End time: ").append(dateFormatter.format(endTime)).append("
"); + } + sb.append("Total ingest time: ").append(getTotalTimeString()).append("
"); + sb.append("Total errors: ").append(errorsTotal).append("
"); + if (errorsTotal > 0) { + sb.append("Errors per service:"); + for (IngestServiceAbstract service : errors.keySet()) { + final int errorsService = errors.get(service); + sb.append("\t").append(service.getName()).append(": ").append(errorsService).append("
"); + } + } + sb.append(""); + return sb.toString(); + } + void start() { startTime = new Date(); } @@ -491,6 +522,14 @@ public class IngestManager { return endTime.getTime() - startTime.getTime(); } + String getStartTimeString() { + return dateFormatter.format(startTime); + } + + String getEndTimeString() { + return dateFormatter.format(endTime); + } + String getTotalTimeString() { long ms = getTotalTime(); long hours = TimeUnit.MILLISECONDS.toHours(ms); @@ -503,7 +542,7 @@ public class IngestManager { return sb.toString(); } - void addError(IngestServiceAbstract source) { + synchronized void addError(IngestServiceAbstract source) { ++errorsTotal; int curServiceError = errors.get(source); errors.put(source, curServiceError + 1); @@ -630,8 +669,13 @@ public class IngestManager { stats.end(); progress.finish(); - //TODO display report - logger.log(Level.INFO, "STATS: " + stats.toString()); + logger.log(Level.INFO, "Summary Report: " + stats.toString()); + //postMessage(IngestMessage.createManagerMessage(stats.toHtmlString())); + JOptionPane.showMessageDialog( + tc, + stats.toHtmlString(), + "Ingest Summary", + JOptionPane.INFORMATION_MESSAGE); } } diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java index 5d9a0daff0..de70542432 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java @@ -82,13 +82,15 @@ public class IngestMessage { StringBuilder sb = new StringBuilder(); sb.append(Long.toString(ID)).append(": "); sb.append("type: ").append(messageType.name()); - sb.append(" source: ").append(source.getName()); + if (source != null) //can be null for manager messages + sb.append(" source: ").append(source.getName()); sb.append(" date: ").append(dateFormat.format(datePosted)); sb.append(" text: ").append(text); if (data != null) sb.append(" data: ").append(data.toString()).append(' '); return sb.toString(); } + @Override public boolean equals(Object obj) { @@ -152,4 +154,9 @@ public class IngestMessage { return im; } + static IngestMessage createManagerMessage(String message) { + IngestMessage im = new IngestMessage(0, MessageType.INFO, null, message); + return im; + } + } diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.form index 8b378ac374..707f10ce45 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.form @@ -52,7 +52,6 @@ - diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java index 911c3866dd..783859f54c 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java @@ -182,7 +182,13 @@ public class IngestMessagePanel extends javax.swing.JPanel { switch (columnIndex) { case 0: - ret = (Object) entry.message.getSource().getName(); + Object service = entry.message.getSource(); + if (service == null) { + ret = ""; + } + else { + ret = (Object) entry.message.getSource().getName(); + } break; case 1: ret = (Object) entry.message.getText(); diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form index b8eeb4467a..de037e4c86 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -53,7 +53,7 @@ - + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java index 3eeef7b914..c90c021689 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -32,7 +32,6 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BoxLayout; import javax.swing.JCheckBox; -import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JSlider; import org.openide.util.NbBundle; @@ -403,8 +402,6 @@ public final class IngestTopComponent extends TopComponent implements DataExplor * Display IngestMessage from service (forwarded by IngestManager) */ void displayMessage(IngestMessage ingestMessage) { - //TODO widget - logger.log(Level.INFO, "INGEST MESSAGE: " + ingestMessage.toString()); messagePanel.addMessage(ingestMessage); } } From 88a54e27864b5722a10868b7390401f8976fad4e Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 27 Jan 2012 16:13:07 -0500 Subject: [PATCH 02/10] Allow user to resize the message inbox --- .../autopsy/ingest/Bundle.properties | 4 +- .../autopsy/ingest/IngestTopComponent.form | 93 ++++++++++++------ .../autopsy/ingest/IngestTopComponent.java | 95 ++++++++++++++----- 3 files changed, 138 insertions(+), 54 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 35f0333705..546a3b145f 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -4,5 +4,7 @@ HINT_IngestTopComponent=Ingest window OpenIDE-Module-Name=Ingest IngestTopComponent.topLable.text=Image ingest services IngestTopComponent.startButton.text=Start -IngestTopComponent.refreshFreqLabel.text=Refresh frequency IngestTopComponent.messageFrame.title=Ingest Messages +IngestTopComponent.refreshFreqLabel.text=Refresh frequency +IngestTopComponent.refreshFrequencyLabel.text=Refresh Frequency +IngestTopComponent.ingestProgressLabel.text=Ingest Progress diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form index de037e4c86..6b6a8d84b3 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -16,12 +16,12 @@ - + - + @@ -29,7 +29,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -48,13 +48,13 @@ - - - + + + - - + + @@ -64,10 +64,10 @@ - - - - + + + + @@ -76,10 +76,10 @@ - - - - + + + + @@ -93,18 +93,22 @@ + + + + - + - + @@ -119,27 +123,40 @@ - + - - + + - + - - + + + + + + + + + + + + + + + - + @@ -155,7 +172,13 @@ - + + + + + + + @@ -236,6 +259,22 @@ + + + + + + + + + + + + + + + + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java index c90c021689..880da70aea 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.ingest; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.beans.PropertyChangeEvent; import java.sql.SQLException; import java.util.ArrayList; @@ -113,7 +115,20 @@ public final class IngestTopComponent extends TopComponent implements DataExplor messagePanel.setOpaque(false); messageFrame.setOpaque(false); - //this.setComponentZOrder(messageFrame, 0); + messageFrame.addComponentListener(new ComponentAdapter() { + + @Override + public void componentResized(ComponentEvent e) { + + super.componentResized(e); + messageFrame.setPreferredSize(messageFrame.getSize()); + } + + + + }); + + //make messageframe on top this.setComponentZOrder(controlPanel, 2); messageFrame.setContentPane(messagePanel); messageFrame.pack(); @@ -162,31 +177,36 @@ public final class IngestTopComponent extends TopComponent implements DataExplor freqSlider = new javax.swing.JSlider(); refreshFreqLabel = new javax.swing.JLabel(); startButton = new javax.swing.JButton(); + refreshFrequencyLabel = new javax.swing.JLabel(); + mainProgressBar = new javax.swing.JProgressBar(); + ingestProgressLabel = new javax.swing.JLabel(); - mainScrollPane.setPreferredSize(new java.awt.Dimension(322, 732)); + mainScrollPane.setPreferredSize(new java.awt.Dimension(322, 749)); - mainPanel.setPreferredSize(new java.awt.Dimension(322, 732)); + mainPanel.setPreferredSize(new java.awt.Dimension(322, 749)); - messageFrame.setBorder(javax.swing.BorderFactory.createMatteBorder(2, 2, 2, 2, new java.awt.Color(204, 204, 255))); + messageFrame.setBorder(new javax.swing.border.LineBorder(javax.swing.UIManager.getDefaults().getColor("InternalFrame.inactiveTitleBackground"), 3, true)); messageFrame.setMaximizable(true); messageFrame.setResizable(true); messageFrame.setTitle(org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.messageFrame.title")); // NOI18N messageFrame.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR)); messageFrame.setFrameIcon(null); + messageFrame.setOpaque(true); + messageFrame.setPreferredSize(new java.awt.Dimension(280, 260)); messageFrame.setVisible(true); javax.swing.GroupLayout messageFrameLayout = new javax.swing.GroupLayout(messageFrame.getContentPane()); messageFrame.getContentPane().setLayout(messageFrameLayout); messageFrameLayout.setHorizontalGroup( messageFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 237, Short.MAX_VALUE) + .addGap(0, 274, Short.MAX_VALUE) ); messageFrameLayout.setVerticalGroup( messageFrameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 227, Short.MAX_VALUE) + .addGap(0, 231, Short.MAX_VALUE) ); - topLable.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + topLable.setFont(new java.awt.Font("Tahoma", 0, 12)); org.openide.awt.Mnemonics.setLocalizedText(topLable, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.topLable.text")); // NOI18N servicesPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); @@ -225,6 +245,10 @@ public final class IngestTopComponent extends TopComponent implements DataExplor } }); + org.openide.awt.Mnemonics.setLocalizedText(refreshFrequencyLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.refreshFrequencyLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(ingestProgressLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.ingestProgressLabel.text")); // NOI18N + javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel); controlPanel.setLayout(controlPanelLayout); controlPanelLayout.setHorizontalGroup( @@ -234,21 +258,31 @@ public final class IngestTopComponent extends TopComponent implements DataExplor .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createSequentialGroup() .addComponent(topLable) - .addContainerGap(114, Short.MAX_VALUE)) + .addContainerGap(153, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createSequentialGroup() - .addComponent(servicesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(31, 31, 31)) + .addComponent(servicesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(70, 70, 70)) .addGroup(controlPanelLayout.createSequentialGroup() .addComponent(startButton) - .addContainerGap(174, Short.MAX_VALUE)) + .addContainerGap(213, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createSequentialGroup() - .addComponent(freqSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(31, Short.MAX_VALUE)))) + .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(mainProgressBar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(freqSlider, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(70, Short.MAX_VALUE)))) + .addGroup(controlPanelLayout.createSequentialGroup() + .addGap(59, 59, 59) + .addComponent(refreshFrequencyLabel) + .addContainerGap(129, Short.MAX_VALUE)) + .addGroup(controlPanelLayout.createSequentialGroup() + .addGap(69, 69, 69) + .addComponent(ingestProgressLabel) + .addContainerGap(135, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createSequentialGroup() .addGap(74, 74, 74) .addComponent(refreshFreqLabel) - .addContainerGap(77, Short.MAX_VALUE))) + .addContainerGap(116, Short.MAX_VALUE))) ); controlPanelLayout.setVerticalGroup( controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -261,7 +295,13 @@ public final class IngestTopComponent extends TopComponent implements DataExplor .addComponent(startButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(freqSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(288, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(refreshFrequencyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(mainProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ingestProgressLabel) + .addContainerGap(228, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createSequentialGroup() .addGap(555, 555, 555) @@ -276,21 +316,21 @@ public final class IngestTopComponent extends TopComponent implements DataExplor .addGroup(mainPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup() + .addComponent(controlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(71, 71, 71)) .addGroup(mainPanelLayout.createSequentialGroup() - .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(71, Short.MAX_VALUE)) - .addGroup(mainPanelLayout.createSequentialGroup() - .addComponent(messageFrame, javax.swing.GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE) - .addGap(71, 71, 71)))) + .addComponent(messageFrame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(48, 48, 48)))) ); mainPanelLayout.setVerticalGroup( mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(mainPanelLayout.createSequentialGroup() .addContainerGap() - .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 297, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(40, 40, 40) - .addComponent(messageFrame) - .addGap(129, 129, 129)) + .addComponent(controlPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 357, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(30, 30, 30) + .addComponent(messageFrame, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(127, 127, 127)) ); mainScrollPane.setViewportView(mainPanel); @@ -299,11 +339,11 @@ public final class IngestTopComponent extends TopComponent implements DataExplor this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 322, Short.MAX_VALUE) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 340, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 732, Short.MAX_VALUE) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 771, Short.MAX_VALUE) ); }// //GEN-END:initComponents @@ -354,10 +394,13 @@ public final class IngestTopComponent extends TopComponent implements DataExplor // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel controlPanel; private javax.swing.JSlider freqSlider; + private javax.swing.JLabel ingestProgressLabel; private javax.swing.JPanel mainPanel; + private javax.swing.JProgressBar mainProgressBar; private javax.swing.JScrollPane mainScrollPane; private javax.swing.JInternalFrame messageFrame; private javax.swing.JLabel refreshFreqLabel; + private javax.swing.JLabel refreshFrequencyLabel; private javax.swing.JPanel servicesPanel; private javax.swing.JButton startButton; private javax.swing.JLabel topLable; From d1ac864a743b794654209e54f74a0cba99d1fec3 Mon Sep 17 00:00:00 2001 From: adam-m Date: Fri, 27 Jan 2012 16:41:04 -0500 Subject: [PATCH 03/10] Update progress bar in explorer and file ingest progresses --- .../autopsy/ingest/Bundle.properties | 2 +- .../autopsy/ingest/IngestManager.java | 27 +++++- .../autopsy/ingest/IngestTopComponent.form | 16 ++-- .../autopsy/ingest/IngestTopComponent.java | 82 ++++++++++--------- 4 files changed, 78 insertions(+), 49 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 546a3b145f..0e6f76bb3e 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -7,4 +7,4 @@ IngestTopComponent.startButton.text=Start IngestTopComponent.messageFrame.title=Ingest Messages IngestTopComponent.refreshFreqLabel.text=Refresh frequency IngestTopComponent.refreshFrequencyLabel.text=Refresh Frequency -IngestTopComponent.ingestProgressLabel.text=Ingest Progress +IngestTopComponent.ingestProgressLabel.text=File Ingest Progress diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index e99cbd09fb..bcec5bc150 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -276,6 +276,27 @@ public class IngestManager { } return ret; } + + private void initMainProgress(final int maximum) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + tc.initProgress(maximum); + } + }); + + + } + + private void updateMainProgress(final int progress) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + tc.updateProgress(progress); + } + }); + + } //manages queue of pending FsContent and IngestServiceFsContent to use on that content //TODO in future content sort will be maintained based on priorities @@ -607,8 +628,8 @@ public class IngestManager { int numFsContents = getNumFsContents(); progress.switchToDeterminate(numFsContents); int processedFiles = 0; + initMainProgress(numFsContents); //process fscontents queue - progress.progress("Running file ingest services."); while (hasNextFsContent()) { QueueUnit unit = getNextFsContent(); for (IngestServiceFsContent service : unit.services) { @@ -628,9 +649,11 @@ public class IngestManager { numFsContents = newFsContents + processedFiles + 1; progress.switchToIndeterminate(); progress.switchToDeterminate(numFsContents); + initMainProgress(numFsContents); } progress.progress("Files", ++processedFiles); + updateMainProgress(processedFiles); --numFsContents; } logger.log(Level.INFO, "Done background processing"); @@ -672,7 +695,7 @@ public class IngestManager { logger.log(Level.INFO, "Summary Report: " + stats.toString()); //postMessage(IngestMessage.createManagerMessage(stats.toHtmlString())); JOptionPane.showMessageDialog( - tc, + null, stats.toHtmlString(), "Ingest Summary", JOptionPane.INFORMATION_MESSAGE); diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form index 6b6a8d84b3..37b22b9920 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -123,40 +123,40 @@ - + - + - + - + - + - + - + - + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java index 880da70aea..31706dd9ca 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -48,7 +48,7 @@ import org.sleuthkit.datamodel.TskException; * Top component explorer for the Ingest module. */ public final class IngestTopComponent extends TopComponent implements DataExplorer { - + private static IngestTopComponent instance; private static final Logger logger = Logger.getLogger(IngestTopComponent.class.getName()); private IngestManager manager = null; @@ -56,14 +56,14 @@ public final class IngestTopComponent extends TopComponent implements DataExplor private Map serviceStates; private IngestMessagePanel messagePanel; private ActionListener serviceSelListener = new ActionListener() { - + @Override public void actionPerformed(ActionEvent ev) { JCheckBox box = (JCheckBox) ev.getSource(); serviceStates.put(box.getName(), box.isSelected()); } }; - + private IngestTopComponent() { services = new ArrayList(); serviceStates = new HashMap(); @@ -73,41 +73,41 @@ public final class IngestTopComponent extends TopComponent implements DataExplor setToolTipText(NbBundle.getMessage(IngestTopComponent.class, "HINT_IngestTopComponent")); //putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE); putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE); - + } - + public static synchronized IngestTopComponent getDefault() { if (instance == null) { instance = new IngestTopComponent(); } return instance; } - + @Override public TopComponent getTopComponent() { return this; } - + @Override public void propertyChange(PropertyChangeEvent evt) { logger.log(Level.INFO, "Unhandled property change: " + evt.getPropertyName()); } - + @Override public int getPersistenceType() { return TopComponent.PERSISTENCE_NEVER; } - + private void customizeComponents() { //custom GUI setup not done by builder freqSlider.setToolTipText("Lower update frequency can optimize performance of certain ingest services, but also reduce real time status feedback"); - + JScrollPane scrollPane = new JScrollPane(servicesPanel); scrollPane.setPreferredSize(this.getSize()); this.add(scrollPane, BorderLayout.CENTER); - + servicesPanel.setLayout(new BoxLayout(servicesPanel, BoxLayout.Y_AXIS)); - + freqSlider.setEnabled(false); @@ -116,25 +116,22 @@ public final class IngestTopComponent extends TopComponent implements DataExplor messagePanel.setOpaque(false); messageFrame.setOpaque(false); messageFrame.addComponentListener(new ComponentAdapter() { - + @Override public void componentResized(ComponentEvent e) { super.componentResized(e); - messageFrame.setPreferredSize(messageFrame.getSize()); + messageFrame.setPreferredSize(messageFrame.getSize()); } - - - }); - + //make messageframe on top this.setComponentZOrder(controlPanel, 2); messageFrame.setContentPane(messagePanel); messageFrame.pack(); messageFrame.setVisible(true); - + Collection imageServices = IngestManager.enumerateImageServices(); for (IngestServiceImage service : imageServices) { @@ -146,7 +143,7 @@ public final class IngestTopComponent extends TopComponent implements DataExplor servicesPanel.add(checkbox); serviceStates.put(serviceName, true); } - + Collection fsServices = IngestManager.enumerateFsContentServices(); for (IngestServiceFsContent service : fsServices) { final String serviceName = service.getName(); @@ -258,31 +255,31 @@ public final class IngestTopComponent extends TopComponent implements DataExplor .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createSequentialGroup() .addComponent(topLable) - .addContainerGap(153, Short.MAX_VALUE)) + .addContainerGap(198, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createSequentialGroup() .addComponent(servicesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(70, 70, 70)) + .addGap(115, 115, 115)) .addGroup(controlPanelLayout.createSequentialGroup() .addComponent(startButton) - .addContainerGap(213, Short.MAX_VALUE)) + .addContainerGap(258, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createSequentialGroup() .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(mainProgressBar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(freqSlider, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(70, Short.MAX_VALUE)))) + .addContainerGap(115, Short.MAX_VALUE)))) .addGroup(controlPanelLayout.createSequentialGroup() .addGap(59, 59, 59) .addComponent(refreshFrequencyLabel) - .addContainerGap(129, Short.MAX_VALUE)) + .addContainerGap(174, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createSequentialGroup() - .addGap(69, 69, 69) + .addGap(59, 59, 59) .addComponent(ingestProgressLabel) - .addContainerGap(135, Short.MAX_VALUE)) + .addContainerGap(171, Short.MAX_VALUE)) .addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(controlPanelLayout.createSequentialGroup() .addGap(74, 74, 74) .addComponent(refreshFreqLabel) - .addContainerGap(116, Short.MAX_VALUE))) + .addContainerGap(161, Short.MAX_VALUE))) ); controlPanelLayout.setVerticalGroup( controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -349,9 +346,10 @@ public final class IngestTopComponent extends TopComponent implements DataExplor private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed - if (manager == null) + if (manager == null) { return; - + } + //pick the services List servicesToStart = new ArrayList(); for (IngestServiceAbstract service : services) { @@ -374,7 +372,7 @@ public final class IngestTopComponent extends TopComponent implements DataExplor images.add(image); } catch (TskException e) { logger.log(Level.SEVERE, "Error ingesting image, can't retrieve image id: " + Integer.toString(imageId), e); - + } catch (SQLException e) { logger.log(Level.SEVERE, "Error ingesting image, can't retrieve image id: " + Integer.toString(imageId), e); } @@ -382,13 +380,13 @@ public final class IngestTopComponent extends TopComponent implements DataExplor manager.execute(servicesToStart, images); }//GEN-LAST:event_startButtonActionPerformed - + private void freqSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_freqSliderStateChanged JSlider source = (JSlider) evt.getSource(); if (!source.getValueIsAdjusting()) { final int refresh = (int) source.getValue(); manager.setUpdateFrequency(refresh); - + } }//GEN-LAST:event_freqSliderStateChanged // Variables declaration - do not modify//GEN-BEGIN:variables @@ -411,7 +409,7 @@ public final class IngestTopComponent extends TopComponent implements DataExplor logger.log(Level.INFO, "IngestTopComponent opened()"); manager = new IngestManager(this); } - + @Override public void componentClosed() { logger.log(Level.INFO, "IngestTopComponent closed()"); @@ -420,17 +418,17 @@ public final class IngestTopComponent extends TopComponent implements DataExplor void enableStartButton(boolean enable) { startButton.setEnabled(enable); } - + void writeProperties(java.util.Properties p) { // better to version settings since initial version as advocated at // http://wiki.apidesign.org/wiki/PropertyFiles p.setProperty("version", "1.0"); - + } - + void readProperties(java.util.Properties p) { String version = p.getProperty("version"); - + } /** @@ -447,4 +445,12 @@ public final class IngestTopComponent extends TopComponent implements DataExplor void displayMessage(IngestMessage ingestMessage) { messagePanel.addMessage(ingestMessage); } + + void initProgress(int maximum) { + this.mainProgressBar.setMaximum(maximum); + } + + void updateProgress(int progress) { + this.mainProgressBar.setValue(progress); + } } From 1cbf3b7a686164ba3db84ce41413e748300e7b80 Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 30 Jan 2012 10:04:38 -0500 Subject: [PATCH 04/10] - move out gui code from ingest manager - when cancelled, don't display report and reset the explorer progress bar --- .../autopsy/ingest/IngestManager.java | 15 +++--- .../autopsy/ingest/IngestMessage.java | 1 - .../autopsy/ingest/IngestTopComponent.form | 47 ++++++++----------- .../autopsy/ingest/IngestTopComponent.java | 8 +++- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index bcec5bc150..2f3417721d 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -33,7 +33,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; -import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; @@ -692,13 +691,10 @@ public class IngestManager { stats.end(); progress.finish(); - logger.log(Level.INFO, "Summary Report: " + stats.toString()); - //postMessage(IngestMessage.createManagerMessage(stats.toHtmlString())); - JOptionPane.showMessageDialog( - null, - stats.toHtmlString(), - "Ingest Summary", - JOptionPane.INFORMATION_MESSAGE); + if (! this.isCancelled()) { + logger.log(Level.INFO, "Summary Report: " + stats.toString()); + tc.displayReport(stats.toHtmlString()); + } } } @@ -719,6 +715,9 @@ public class IngestManager { //empty queues emptyFsContents(); emptyImages(); + + //reset main progress bar + initMainProgress(0); } } diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java index de70542432..abce9b0fbf 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.ingest; import java.text.SimpleDateFormat; import java.util.Date; -import javax.swing.text.DateFormatter; import org.sleuthkit.autopsy.datamodel.KeyValueThing; /** diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form index 37b22b9920..f09fc077f3 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -119,38 +119,29 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + - + + + + + + + + - - - - - - - - - - + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java index 31706dd9ca..0711b33bca 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -34,6 +34,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BoxLayout; import javax.swing.JCheckBox; +import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JSlider; import org.openide.util.NbBundle; @@ -435,8 +436,11 @@ public final class IngestTopComponent extends TopComponent implements DataExplor * Display ingest summary report in some dialog */ void displayReport(String ingestReport) { - //TODO widget - logger.log(Level.INFO, "INGEST REPORT: " + ingestReport); + JOptionPane.showMessageDialog( + null, + ingestReport, + "Ingest Summary", + JOptionPane.INFORMATION_MESSAGE); } /** From 44edb982192f722987be710aab4f13e1763edcd4 Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 30 Jan 2012 10:11:37 -0500 Subject: [PATCH 05/10] Added method to manager to enable queing of single image and multiple services (e.g. from wizard) --- .../autopsy/ingest/IngestManager.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 2f3417721d..1eb5fc8747 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -81,21 +81,30 @@ public class IngestManager { } /** - * IngestManager entry point, enqueues image to be processed. - * Spawns background thread which enumerates all sorted files and executes chosen services per file in a pre-determined order. - * Notifies services when work is complete or should be interrupted using complete() and stop() calls. - * Does not block and can be called multiple times to enqueue more work to already running background process. + * Multiple image version of execute, enqueues multiple images and associated services at once + * @param services services to execute on every image + * @param images images to execute services on */ void execute(final Collection services, final Collection images) { - - //queuing start tc.enableStartButton(false); SwingWorker queueWorker = new EnqueueWorker(services, images); queueWorker.execute(); - logger.log(Level.INFO, "Queues: " + imageQueue.toString() + " " + fsContentQueue.toString()); - - + //logger.log(Level.INFO, "Queues: " + imageQueue.toString() + " " + fsContentQueue.toString()); + } + + /** + * IngestManager entry point, enqueues image to be processed. + * Spawns background thread which enumerates all sorted files and executes chosen services per file in a pre-determined order. + * Notifies services when work is complete or should be interrupted using complete() and stop() calls. + * Does not block and can be called multiple times to enqueue more work to already running background process. + * @param services services to execute on the image + * @param image image to execute services on + */ + void execute(final Collection services, final Image image) { + Collection images = new ArrayList(); + images.add(image); + execute(services, images); } private void startAll() { From 601abce8a3bc1c717931a8fa727141a06ee786f6 Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 30 Jan 2012 10:28:27 -0500 Subject: [PATCH 06/10] use separate mutexes for image and fscontent queues use os independent EOL --- .../autopsy/ingest/IngestManager.java | 111 +++++++----------- 1 file changed, 41 insertions(+), 70 deletions(-) diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 1eb5fc8747..7e61a2891f 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -57,7 +57,6 @@ public class IngestManager { private IngestManagerStats stats; private int updateFrequency; //queues - private final Object queueLock = new Object(); private final ImageQueue imageQueue = new ImageQueue(); private final FsContentQueue fsContentQueue = new FsContentQueue(); private IngestThread ingester; @@ -92,7 +91,7 @@ public class IngestManager { //logger.log(Level.INFO, "Queues: " + imageQueue.toString() + " " + fsContentQueue.toString()); } - + /** * IngestManager entry point, enqueues image to be processed. * Spawns background thread which enumerates all sorted files and executes chosen services per file in a pre-determined order. @@ -102,9 +101,9 @@ public class IngestManager { * @param image image to execute services on */ void execute(final Collection services, final Image image) { - Collection images = new ArrayList(); - images.add(image); - execute(services, images); + Collection images = new ArrayList(); + images.add(image); + execute(services, images); } private void startAll() { @@ -194,24 +193,15 @@ public class IngestManager { } private void addImage(IngestServiceImage service, Image image) { - - synchronized (queueLock) { - imageQueue.enqueue(image, service); - //queueLock.notifyAll(); - } - - + imageQueue.enqueue(image, service); } private void addFsContent(IngestServiceFsContent service, Image image) { Collection fsContents = new GetAllFilesContentVisitor().visit(image); - synchronized (queueLock) { - for (FsContent fsContent : fsContents) { - fsContentQueue.enqueue(fsContent, service); - } - //queueLock.notifyAll(); + + for (FsContent fsContent : fsContents) { + fsContentQueue.enqueue(fsContent, service); } - //logger.log(Level.INFO, fsContentQueue.toString()); } /** @@ -221,39 +211,28 @@ public class IngestManager { */ private QueueUnit getNextFsContent() { QueueUnit ret = null; - synchronized (queueLock) { - ret = fsContentQueue.dequeue(); - - } + ret = fsContentQueue.dequeue(); return ret; } private boolean hasNextFsContent() { boolean ret = false; - synchronized (queueLock) { - ret = fsContentQueue.hasNext(); - } + ret = fsContentQueue.hasNext(); return ret; } private int getNumFsContents() { int ret = 0; - synchronized (queueLock) { - ret = fsContentQueue.getCount(); - } + ret = fsContentQueue.getCount(); return ret; } private void emptyFsContents() { - synchronized (queueLock) { - fsContentQueue.empty(); - } + fsContentQueue.empty(); } private void emptyImages() { - synchronized (queueLock) { - imageQueue.empty(); - } + imageQueue.empty(); } /** @@ -263,28 +242,22 @@ public class IngestManager { */ private QueueUnit getNextImage() { QueueUnit ret = null; - synchronized (queueLock) { - ret = imageQueue.dequeue(); - } + ret = imageQueue.dequeue(); return ret; } private boolean hasNextImage() { boolean ret = false; - synchronized (queueLock) { - ret = imageQueue.hasNext(); - } + ret = imageQueue.hasNext(); return ret; } private int getNumImages() { int ret = 0; - synchronized (queueLock) { - ret = imageQueue.getCount(); - } + ret = imageQueue.getCount(); return ret; } - + private void initMainProgress(final int maximum) { SwingUtilities.invokeLater(new Runnable() { @Override @@ -292,10 +265,8 @@ public class IngestManager { tc.initProgress(maximum); } }); - - } - + private void updateMainProgress(final int progress) { SwingUtilities.invokeLater(new Runnable() { @Override @@ -303,7 +274,6 @@ public class IngestManager { tc.updateProgress(progress); } }); - } //manages queue of pending FsContent and IngestServiceFsContent to use on that content @@ -312,7 +282,7 @@ public class IngestManager { List> fsContentUnits = new ArrayList>(); - void enqueue(FsContent fsContent, IngestServiceFsContent service) { + synchronized void enqueue(FsContent fsContent, IngestServiceFsContent service) { QueueUnit found = findFsContent(fsContent); if (found != null) { @@ -326,7 +296,7 @@ public class IngestManager { } } - void enqueue(FsContent fsContent, Collection services) { + synchronized void enqueue(FsContent fsContent, Collection services) { QueueUnit found = findFsContent(fsContent); if (found != null) { @@ -340,19 +310,19 @@ public class IngestManager { } } - boolean hasNext() { + synchronized boolean hasNext() { return !fsContentUnits.isEmpty(); } - int getCount() { + synchronized int getCount() { return fsContentUnits.size(); } - void empty() { + synchronized void empty() { fsContentUnits.clear(); } - QueueUnit dequeue() { + synchronized QueueUnit dequeue() { if (!hasNext()) { throw new UnsupportedOperationException("FsContent processing queue is empty"); } @@ -372,7 +342,7 @@ public class IngestManager { } @Override - public String toString() { + synchronized public String toString() { return "FsContentQueue, size: " + Integer.toString(fsContentUnits.size()); } } @@ -382,7 +352,7 @@ public class IngestManager { List> imageUnits = new ArrayList>(); - void enqueue(Image image, IngestServiceImage service) { + synchronized void enqueue(Image image, IngestServiceImage service) { QueueUnit found = findImage(image); if (found != null) { @@ -396,7 +366,7 @@ public class IngestManager { } } - void enqueue(Image image, Collection services) { + synchronized void enqueue(Image image, Collection services) { QueueUnit found = findImage(image); if (found != null) { @@ -410,19 +380,19 @@ public class IngestManager { } } - boolean hasNext() { + synchronized boolean hasNext() { return !imageUnits.isEmpty(); } - int getCount() { + synchronized int getCount() { return imageUnits.size(); } - void empty() { + synchronized void empty() { imageUnits.clear(); } - QueueUnit dequeue() { + synchronized QueueUnit dequeue() { if (!hasNext()) { throw new UnsupportedOperationException("Image processing queue is empty"); } @@ -430,7 +400,7 @@ public class IngestManager { return imageUnits.remove(0); } - private QueueUnit findImage(Image image) { + private synchronized QueueUnit findImage(Image image) { QueueUnit found = null; for (QueueUnit unit : imageUnits) { if (unit.content.equals(image)) { @@ -442,7 +412,7 @@ public class IngestManager { } @Override - public String toString() { + public synchronized String toString() { return "ImageQueue, size: " + Integer.toString(imageUnits.size()); } } @@ -495,20 +465,21 @@ public class IngestManager { @Override public String toString() { + final String EOL = System.getProperty("line.separator"); StringBuilder sb = new StringBuilder(); if (startTime != null) { - sb.append("Start time: ").append(dateFormatter.format(startTime)).append("\n"); + sb.append("Start time: ").append(dateFormatter.format(startTime)).append(EOL); } if (endTime != null) { - sb.append("End time: ").append(dateFormatter.format(endTime)).append("\n"); + sb.append("End time: ").append(dateFormatter.format(endTime)).append(EOL); } - sb.append("Total ingest time: ").append(getTotalTimeString()).append("\n"); - sb.append("Total errors: ").append(errorsTotal).append("\n"); + sb.append("Total ingest time: ").append(getTotalTimeString()).append(EOL); + sb.append("Total errors: ").append(errorsTotal).append(EOL); if (errorsTotal > 0) { sb.append("Errors per service:"); for (IngestServiceAbstract service : errors.keySet()) { final int errorsService = errors.get(service); - sb.append("\t").append(service.getName()).append(": ").append(errorsService).append("\n"); + sb.append("\t").append(service.getName()).append(": ").append(errorsService).append(EOL); } } return sb.toString(); @@ -700,7 +671,7 @@ public class IngestManager { stats.end(); progress.finish(); - if (! this.isCancelled()) { + if (!this.isCancelled()) { logger.log(Level.INFO, "Summary Report: " + stats.toString()); tc.displayReport(stats.toHtmlString()); } @@ -724,7 +695,7 @@ public class IngestManager { //empty queues emptyFsContents(); emptyImages(); - + //reset main progress bar initMainProgress(0); } From 45c41e363a7bee73336fb927bee37067fda37c56 Mon Sep 17 00:00:00 2001 From: adam-m Date: Mon, 30 Jan 2012 17:30:08 -0500 Subject: [PATCH 07/10] 1. implemented multiple image workers and services (1 per image), concurrently 2. added image worker controller API for service to report progress and cancel itself 3. handled case change while ingesting 4. do not try to enqueue work if no images/services selected --- .../autopsy/ingest/IngestImageThread.java | 117 ++++++++ .../ingest/IngestImageWorkerController.java | 58 ++++ .../autopsy/ingest/IngestManager.java | 271 +++++++++++------- .../autopsy/ingest/IngestMessagePanel.java | 11 +- .../autopsy/ingest/IngestServiceImage.java | 5 +- .../autopsy/ingest/IngestTopComponent.form | 4 +- .../autopsy/ingest/IngestTopComponent.java | 22 +- .../example/ExampleImageIngestService.java | 63 ++-- .../org/sleuthkit/autopsy/ingest/layer.xml | 3 +- 9 files changed, 433 insertions(+), 121 deletions(-) create mode 100644 Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java create mode 100644 Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageWorkerController.java diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java new file mode 100644 index 0000000000..0d7fe8d953 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageThread.java @@ -0,0 +1,117 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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.ingest; + +//ingester worker for image queue +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.util.Cancellable; +import org.sleuthkit.datamodel.Image; + +/** + * worker for every ingest image service + * there is a separate instance per image / service pair + */ +public class IngestImageThread extends SwingWorker { + + private Logger logger = Logger.getLogger(IngestImageThread.class.getName()); + private ProgressHandle progress; + private Image image; + private IngestServiceImage service; + private IngestImageWorkerController controller; + private IngestManager manager; + + IngestImageThread(IngestManager manager, Image image, IngestServiceImage service) { + this.manager = manager; + this.image = image; + this.service = service; + } + + Image getImage() { + return image; + } + + IngestServiceImage getService() { + return service; + } + + @Override + protected Object doInBackground() throws Exception { + + logger.log(Level.INFO, "Starting background processing"); + + progress = ProgressHandleFactory.createHandle(service.getName() + " img:" + image.getId(), new Cancellable() { + + @Override + public boolean cancel() { + return IngestImageThread.this.cancel(true); + } + }); + + progress.start(); + progress.switchToIndeterminate(); + + controller = new IngestImageWorkerController(this, progress); + + if (isCancelled()) { + return null; + } + try { + service.process(image, controller); + } catch (Exception e) { + logger.log(Level.INFO, "Exception from service: " + service.getName(), e); + } + logger.log(Level.INFO, + "Done background processing"); + return null; + } + + @Override + protected void done() { + try { + super.get(); //block and get all exceptions thrown while doInBackground() + //notify services of completion + if (!this.isCancelled()) { + service.complete(); + } + } catch (CancellationException e) { + //task was cancelled + service.stop(); + + } catch (InterruptedException ex) { + service.stop(); + } catch (ExecutionException ex) { + service.stop(); + logger.log(Level.SEVERE, "Fatal error during image ingest.", ex); + } catch (Exception ex) { + service.stop(); + logger.log(Level.SEVERE, "Fatal error during image ingest.", ex); + } finally { + progress.finish(); + + //cleanup queues (worker and image/service) + manager.removeImageIngestWorker(this); + } + } +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageWorkerController.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageWorkerController.java new file mode 100644 index 0000000000..4e07285404 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestImageWorkerController.java @@ -0,0 +1,58 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit 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.ingest; + +import org.netbeans.api.progress.ProgressHandle; + +/** + * passed to the service as a limited way to control this worker + * update progress bar, check if job is cancelled + */ +public class IngestImageWorkerController { + + private IngestImageThread worker; + private ProgressHandle progress; + + public IngestImageWorkerController(IngestImageThread worker, ProgressHandle progress) { + this.worker = worker; + this.progress = progress; + } + + public boolean isCancelled() { + return worker.isCancelled(); + } + + public void switchToDeterminate(int workUnits) { + if (progress != null) { + progress.switchToDeterminate(workUnits); + } + } + + public void switchToInDeterminate() { + if (progress != null) { + progress.switchToIndeterminate(); + } + } + + public void progress(int workUnits) { + if (progress != null) { + progress.progress(worker.getImage().getName(), workUnits); + } + } +} \ No newline at end of file diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java index 7e61a2891f..a726411b9f 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -59,7 +59,11 @@ public class IngestManager { //queues private final ImageQueue imageQueue = new ImageQueue(); private final FsContentQueue fsContentQueue = new FsContentQueue(); - private IngestThread ingester; + private final Object queuesLock = new Object(); + //workers + private IngestFsContentThread fsContentIngester; + private List imageIngesters; + //services final Collection imageServices = enumerateImageServices(); final Collection fsContentServices = enumerateFsContentServices(); @@ -70,10 +74,15 @@ public class IngestManager { IngestManager(IngestTopComponent tc) { this.tc = tc; + imageIngesters = new ArrayList(); + //one time initialization of services - for (IngestServiceImage s : imageServices) { - s.init(this); - } + + //image services are now initialized per instance + //for (IngestServiceImage s : imageServices) { + // s.init(this); + //} + for (IngestServiceFsContent s : fsContentServices) { s.init(this); } @@ -106,27 +115,92 @@ public class IngestManager { execute(services, images); } + /** + * manage current workers + * if fsContent service is still running, do nothing and allow it to consume queue + * otherwise start /restart fsContent worker + * + * image workers run per (service,image). Check if one for the (service,image) is already running + * otherwise start/restart the worker + */ private void startAll() { - boolean start = false; - if (ingester == null) { - start = true; + //image ingesters + while (hasNextImage()) { + //dequeue + final QueueUnit qu = + this.getNextImage(); + //check if such (service,image) already running - } //if worker had completed, restart it in case data is still enqueued - else if (ingester.isDone() - && (hasNextFsContent() || hasNextImage())) { - logger.log(Level.INFO, "Restarting ingester thread."); - start = true; + for (IngestServiceImage quService : qu.services) { + boolean alreadyRunning = false; + for (IngestImageThread worker : imageIngesters) { + if (!worker.getImage().equals(qu.content)) { + continue; //check next worker + } + //same image, check service (by name, not id, since different instances) + if (worker.getService().getName().equals(quService.getName())) { + alreadyRunning = true; + logger.log(Level.INFO, "Image Ingester <" + qu.content + ", " + quService.getName() + "> is already running"); + break; + } + } + //checked all workers + if (alreadyRunning == false) { + logger.log(Level.INFO, "Starting new image Ingester <" + qu.content + ", " + quService.getName() + ">"); + IngestImageThread newImageWorker = new IngestImageThread(this, qu.content, quService); + imageIngesters.add(newImageWorker); + //image services are now initialized per instance + quService.init(this); + newImageWorker.execute(); + } + } + } + + //merge with queue (will not add if already exists) + + //fsContent ingester + boolean startFsContentIngester = false; + if (hasNextFsContent()) { + if (fsContentIngester + == null) { + startFsContentIngester = true; + logger.log(Level.INFO, "Satrting initial FsContent Ingester"); + } //if worker had completed, restart it in case data is still enqueued + else if (fsContentIngester.isDone()) { + startFsContentIngester = true; + logger.log(Level.INFO, "Restarting fsContent ingester thread."); + } } else { - logger.log(Level.INFO, "Ingester is still running"); + logger.log(Level.INFO, "no new FsContent enqueued, no ingester needed"); } - if (start) { - logger.log(Level.INFO, "Starting new ingester."); - ingester = new IngestThread(); + + if (startFsContentIngester) { + fsContentIngester = new IngestFsContentThread(); stats = new IngestManagerStats(); - ingester.execute(); + fsContentIngester.execute(); + } + } + + + /** + * stop currently running threads if any (e.g. when changing a case) + */ + void stopAll() { + //empty queues + emptyFsContents(); + emptyImages(); + + //stop workers + if (fsContentIngester != null) { + fsContentIngester.cancel(true); + fsContentIngester = null; + } + + for (IngestImageThread imageWorker : imageIngesters) { + imageWorker.cancel(true); + removeImageIngestWorker(imageWorker); } - } /** @@ -193,14 +267,18 @@ public class IngestManager { } private void addImage(IngestServiceImage service, Image image) { - imageQueue.enqueue(image, service); + synchronized (queuesLock) { + imageQueue.enqueue(image, service); + } } private void addFsContent(IngestServiceFsContent service, Image image) { Collection fsContents = new GetAllFilesContentVisitor().visit(image); - for (FsContent fsContent : fsContents) { - fsContentQueue.enqueue(fsContent, service); + synchronized (queuesLock) { + for (FsContent fsContent : fsContents) { + fsContentQueue.enqueue(fsContent, service); + } } } @@ -211,28 +289,38 @@ public class IngestManager { */ private QueueUnit getNextFsContent() { QueueUnit ret = null; - ret = fsContentQueue.dequeue(); + synchronized (queuesLock) { + ret = fsContentQueue.dequeue(); + } return ret; } private boolean hasNextFsContent() { boolean ret = false; - ret = fsContentQueue.hasNext(); + synchronized (queuesLock) { + ret = fsContentQueue.hasNext(); + } return ret; } private int getNumFsContents() { int ret = 0; - ret = fsContentQueue.getCount(); + synchronized (queuesLock) { + ret = fsContentQueue.getCount(); + } return ret; } private void emptyFsContents() { - fsContentQueue.empty(); + synchronized (queuesLock) { + fsContentQueue.empty(); + } } private void emptyImages() { - imageQueue.empty(); + synchronized (queuesLock) { + imageQueue.empty(); + } } /** @@ -242,19 +330,25 @@ public class IngestManager { */ private QueueUnit getNextImage() { QueueUnit ret = null; - ret = imageQueue.dequeue(); + synchronized (queuesLock) { + ret = imageQueue.dequeue(); + } return ret; } private boolean hasNextImage() { boolean ret = false; - ret = imageQueue.hasNext(); + synchronized (queuesLock) { + ret = imageQueue.hasNext(); + } return ret; } private int getNumImages() { int ret = 0; - ret = imageQueue.getCount(); + synchronized (queuesLock) { + ret = imageQueue.getCount(); + } return ret; } @@ -276,13 +370,19 @@ public class IngestManager { }); } + //image worker to remove itself when complete or interrupted + synchronized void removeImageIngestWorker(IngestImageThread worker) { + //remove worker + imageIngesters.remove(worker); + } + //manages queue of pending FsContent and IngestServiceFsContent to use on that content //TODO in future content sort will be maintained based on priorities private class FsContentQueue { List> fsContentUnits = new ArrayList>(); - synchronized void enqueue(FsContent fsContent, IngestServiceFsContent service) { + void enqueue(FsContent fsContent, IngestServiceFsContent service) { QueueUnit found = findFsContent(fsContent); if (found != null) { @@ -296,7 +396,7 @@ public class IngestManager { } } - synchronized void enqueue(FsContent fsContent, Collection services) { + void enqueue(FsContent fsContent, Collection services) { QueueUnit found = findFsContent(fsContent); if (found != null) { @@ -310,19 +410,19 @@ public class IngestManager { } } - synchronized boolean hasNext() { + boolean hasNext() { return !fsContentUnits.isEmpty(); } - synchronized int getCount() { + int getCount() { return fsContentUnits.size(); } - synchronized void empty() { + void empty() { fsContentUnits.clear(); } - synchronized QueueUnit dequeue() { + QueueUnit dequeue() { if (!hasNext()) { throw new UnsupportedOperationException("FsContent processing queue is empty"); } @@ -342,17 +442,17 @@ public class IngestManager { } @Override - synchronized public String toString() { + public synchronized String toString() { return "FsContentQueue, size: " + Integer.toString(fsContentUnits.size()); } } - //manages queue of pending Images and IngestServiceImage to use on that image +//manages queue of pending Images and IngestServiceImage to use on that image private class ImageQueue { List> imageUnits = new ArrayList>(); - synchronized void enqueue(Image image, IngestServiceImage service) { + void enqueue(Image image, IngestServiceImage service) { QueueUnit found = findImage(image); if (found != null) { @@ -366,7 +466,7 @@ public class IngestManager { } } - synchronized void enqueue(Image image, Collection services) { + void enqueue(Image image, Collection services) { QueueUnit found = findImage(image); if (found != null) { @@ -380,19 +480,19 @@ public class IngestManager { } } - synchronized boolean hasNext() { + boolean hasNext() { return !imageUnits.isEmpty(); } - synchronized int getCount() { + int getCount() { return imageUnits.size(); } - synchronized void empty() { + void empty() { imageUnits.clear(); } - synchronized QueueUnit dequeue() { + QueueUnit dequeue() { if (!hasNext()) { throw new UnsupportedOperationException("Image processing queue is empty"); } @@ -400,7 +500,7 @@ public class IngestManager { return imageUnits.remove(0); } - private synchronized QueueUnit findImage(Image image) { + private QueueUnit findImage(Image image) { QueueUnit found = null; for (QueueUnit unit : imageUnits) { if (unit.content.equals(image)) { @@ -438,11 +538,14 @@ public class IngestManager { } //merge services with the current collection of services per image - //this assumes that there is one singleton instance of each type of service + //this assumes singleton instances of every service type for correct merge + //in case of multiple instances, they need to be handled correctly after dequeue() final void addAll(Collection services) { this.services.addAll(services); } + //this assumes singleton instances of every service type for correct merge + //in case of multiple instances, they need to be handled correctly after dequeue() final void add(S service) { this.services.add(service); } @@ -549,12 +652,12 @@ public class IngestManager { } } - //ingester worker doing work in background - //in current design, worker runs until queues are consumed - //and if needed, it is restarted when data arrives - private class IngestThread extends SwingWorker { +//ingester worker for fsContent queue +//worker runs until fsContent queue is consumed +//and if needed, new instance is created and started when data arrives + private class IngestFsContentThread extends SwingWorker { - private Logger logger = Logger.getLogger(IngestThread.class.getName()); + private Logger logger = Logger.getLogger(IngestFsContentThread.class.getName()); private ProgressHandle progress; @Override @@ -563,46 +666,15 @@ public class IngestManager { logger.log(Level.INFO, "Starting background processing"); stats.start(); - progress = ProgressHandleFactory.createHandle("Ingesting", new Cancellable() { + progress = ProgressHandleFactory.createHandle("File Ingest", new Cancellable() { @Override public boolean cancel() { - return IngestThread.this.cancel(true); + return IngestFsContentThread.this.cancel(true); } }); progress.start(); - progress.switchToIndeterminate(); - int numImages = getNumImages(); - progress.switchToDeterminate(numImages); - int processedImages = 0; - //process image queue - while (hasNextImage()) { - QueueUnit unit = getNextImage(); - for (IngestServiceImage service : unit.services) { - if (isCancelled()) { - return null; - } - - try { - service.process(unit.content); - } catch (Exception e) { - logger.log(Level.INFO, "Exception from service: " + service.getName(), e); - stats.addError(service); - } - //check if new files enqueued - int newImages = getNumImages(); - if (newImages > numImages) { - numImages = newImages + processedImages + 1; - progress.switchToIndeterminate(); - progress.switchToDeterminate(numImages); - - } - progress.progress("Images (" + service.getName() + ")", ++processedImages); - --numImages; - } - } - progress.switchToIndeterminate(); int numFsContents = getNumFsContents(); progress.switchToDeterminate(numFsContents); @@ -679,22 +751,12 @@ public class IngestManager { } - @Override - protected void process(List chunks) { - super.process(chunks); - } - private void handleInterruption() { - for (IngestServiceImage s : imageServices) { - s.stop(); - } - for (IngestServiceFsContent s : fsContentServices) { s.stop(); } //empty queues emptyFsContents(); - emptyImages(); //reset main progress bar initMainProgress(0); @@ -737,7 +799,6 @@ public class IngestManager { } catch (CancellationException e) { //task was cancelled handleInterruption(); - } catch (InterruptedException ex) { handleInterruption(); } catch (ExecutionException ex) { @@ -751,13 +812,11 @@ public class IngestManager { //queing end if (this.isCancelled()) { //empty queues - emptyFsContents(); - emptyImages(); + handleInterruption(); } else { //start ingest workers startAll(); } - progress.finish(); tc.enableStartButton(true); } @@ -768,13 +827,29 @@ public class IngestManager { for (Image image : images) { final String imageName = image.getName(); for (IngestServiceAbstract service : services) { + if (isCancelled()) { + return; + } final String serviceName = service.getName(); progress.progress(serviceName + " " + imageName, processed); switch (service.getType()) { case Image: - addImage((IngestServiceImage) service, image); + //enqueue a new instance of image service + //Class serviceClass = service.getClass(); + //serviceClass. + try { + final IngestServiceImage newServiceInstance = (IngestServiceImage) (service.getClass()).newInstance(); + addImage(newServiceInstance, image); + } catch (InstantiationException e) { + logger.log(Level.SEVERE, "Cannot instantiate service: " + service.getName(), e); + } catch (IllegalAccessException e) { + logger.log(Level.SEVERE, "Cannot instantiate service: " + service.getName(), e); + } + + //addImage((IngestServiceImage) service, image); break; case FsContent: + //enqueue the same singleton fscontent service addFsContent((IngestServiceFsContent) service, image); break; default: diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java index 783859f54c..2d6e83ca52 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessagePanel.java @@ -135,6 +135,10 @@ public class IngestMessagePanel extends javax.swing.JPanel { //autoscroll messageTable.scrollRectToVisible(messageTable.getCellRect(messageTable.getRowCount() - 1, messageTable.getColumnCount(), true)); } + + public void clearMessages() { + tableModel.clearMessages(); + } private void setVisited(int rowNumber) { tableModel.setVisited(rowNumber); @@ -213,7 +217,12 @@ public class IngestMessagePanel extends javax.swing.JPanel { public void addMessage(IngestMessage m) { messageData.add(new TableEntry(m)); int size = messageData.size(); - this.fireTableRowsInserted(size - 1, size); //TODO check + this.fireTableRowsInserted(size - 1, size); + } + + public void clearMessages() { + messageData.clear(); + fireTableDataChanged(); } public void setVisited(int rowNumber) { diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java index 6eb7cfe124..03eb7e6733 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java @@ -30,6 +30,9 @@ public interface IngestServiceImage extends IngestServiceAbstract { * notification from manager to process image * The service notifies viewers via IngestManager.postMessage() * and may also write results to the black-board as it is processing. + * + * @param image image to process + * @param controller controller to the worker, to update progress (if determinate) and check if cancelled */ - public void process(Image image); + public void process(Image image, IngestImageWorkerController controller); } \ No newline at end of file diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form index f09fc077f3..4240eb7d0e 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -141,13 +141,13 @@ - + - + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java index 0711b33bca..ff6d36c3fb 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -24,6 +24,7 @@ import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @@ -132,6 +133,24 @@ public final class IngestTopComponent extends TopComponent implements DataExplor messageFrame.pack(); messageFrame.setVisible(true); + //handle case change + Case.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) { + Case oldCase = (Case) evt.getOldValue(); + if (oldCase == null) + //nothing to do, not case had been opened + return; + //clear inbox + messagePanel.clearMessages(); + //stop workers if running + if (manager != null) + manager.stopAll(); + } + } + + }); Collection imageServices = IngestManager.enumerateImageServices(); @@ -379,7 +398,8 @@ public final class IngestTopComponent extends TopComponent implements DataExplor } } - manager.execute(servicesToStart, images); + if (! services.isEmpty() && ! images.isEmpty()) + manager.execute(servicesToStart, images); }//GEN-LAST:event_startButtonActionPerformed private void freqSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_freqSliderStateChanged diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/example/ExampleImageIngestService.java b/Ingest/src/org/sleuthkit/autopsy/ingest/example/ExampleImageIngestService.java index f8fdd5086a..2124e996c0 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/example/ExampleImageIngestService.java +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/example/ExampleImageIngestService.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.ingest.example; import java.util.logging.Level; import java.util.logging.Logger; +import org.sleuthkit.autopsy.ingest.IngestImageWorkerController; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestMessage; import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; @@ -33,26 +34,53 @@ import org.sleuthkit.datamodel.Image; public final class ExampleImageIngestService implements IngestServiceImage { private static final Logger logger = Logger.getLogger(ExampleImageIngestService.class.getName()); - private static ExampleImageIngestService instance = null; + private static ExampleImageIngestService defaultInstance = null; private IngestManager manager; - private static int messageId = 0; + //public constructor is required + //as multiple instances are created for processing multiple images simultenously + public ExampleImageIngestService() { + } + + //default instance used for service registration public static synchronized ExampleImageIngestService getDefault() { - if (instance == null) { - instance = new ExampleImageIngestService(); + if (defaultInstance == null) { + defaultInstance = new ExampleImageIngestService(); } - return instance; + return defaultInstance; } @Override - public void process(Image image) { + public void process(Image image, IngestImageWorkerController controller) { + logger.log(Level.INFO, "process() " + this.toString()); + manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "Processing " + image.getName())); //service specific Image processing code here - try { - Thread.sleep(5000); - } catch (InterruptedException e) { + //example: + + //if we know amount of work units, we can switch to determinate and update progress bar + int filesToProcess = 100; + controller.switchToDeterminate(filesToProcess); + int processedFiles = 0; + + while (filesToProcess-- > 0) { + + //check if should terminate on every loop iteration + if (controller.isCancelled()) { + return; + } + try { + //do the work + Thread.sleep(500); + //post message to user if found something interesting + manager.postMessage(IngestMessage.createMessage(processedFiles, MessageType.INFO, this, "Processed " + image.getName() + ": " + Integer.toString(processedFiles))); + + //update progress + controller.progress(++processedFiles); + } catch (InterruptedException e) { + } } @@ -60,10 +88,11 @@ public final class ExampleImageIngestService implements IngestServiceImage { @Override public void complete() { - logger.log(Level.INFO, "complete()"); - manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "COMPLETE")); - - //service specific cleanup due completion here + logger.log(Level.INFO, "complete() " + this.toString()); + + manager.postMessage(IngestMessage.createMessage(++messageId, MessageType.INFO, this, "completed image processing")); + + //service specific cleanup due to completion here } @Override @@ -73,18 +102,18 @@ public final class ExampleImageIngestService implements IngestServiceImage { @Override public void init(IngestManager manager) { - logger.log(Level.INFO, "init()"); + logger.log(Level.INFO, "init() " + this.toString()); this.manager = manager; //service specific initialization here - + } @Override public void stop() { logger.log(Level.INFO, "stop()"); - - //service specific cleanup due interruption here + + //service specific cleanup due to interruption here } @Override diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml b/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml index b324999edb..0671f6e101 100644 --- a/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml @@ -8,12 +8,13 @@ - + diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java index a152a75f06..35760639da 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java @@ -49,7 +49,7 @@ public final class KeywordSearchIngestService implements IngestServiceFsContent Thread.sleep(100); } catch (InterruptedException e) {} - manager.postMessage(IngestMessage.createMessage(1, MessageType.INFO, this, "Processing " + fsContent.getName())); + //manager.postMessage(IngestMessage.createMessage(1, MessageType.INFO, this, "Processing " + fsContent.getName())); }