/*
* Autopsy Forensic Browser
*
* Copyright 2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.ingest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.swing.JDialog;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import org.apache.commons.lang3.time.DurationFormatUtils;
import org.openide.util.NbBundle;
/**
* A panel that displays ingest task progress snapshots.
*/
public class IngestProgressSnapshotPanel extends javax.swing.JPanel {
private final JDialog parent;
private final IngestThreadActivitySnapshotsTableModel threadActivityTableModel;
private final IngestJobTableModel jobTableModel;
private final ModuleTableModel moduleTableModel;
IngestProgressSnapshotPanel(JDialog parent) {
this.parent = parent;
threadActivityTableModel = new IngestThreadActivitySnapshotsTableModel();
jobTableModel = new IngestJobTableModel();
moduleTableModel = new ModuleTableModel();
initComponents();
customizeComponents();
}
private void customizeComponents() {
threadActivitySnapshotsTable.setModel(threadActivityTableModel);
jobTable.setModel(jobTableModel);
moduleTable.setModel(moduleTableModel);
int width = snapshotsScrollPane.getPreferredSize().width;
for (int i = 0; i < threadActivitySnapshotsTable.getColumnCount(); ++i) {
TableColumn column = threadActivitySnapshotsTable.getColumnModel().getColumn(i);
switch (i) {
case 0:
column.setPreferredWidth(((int) (width * 0.02)));
break;
case 1:
column.setPreferredWidth(((int) (width * 0.20)));
break;
case 2:
column.setPreferredWidth(((int) (width * 0.15)));
break;
case 3:
column.setPreferredWidth(((int) (width * 0.35)));
break;
case 4:
column.setPreferredWidth(((int) (width * 0.18)));
break;
case 5:
column.setPreferredWidth(((int) (width * 0.10)));
break;
}
}
threadActivitySnapshotsTable.setFillsViewportHeight(true);
}
private class IngestThreadActivitySnapshotsTableModel extends AbstractTableModel {
private final String[] columnNames = {NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.threadID"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.dataSource"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.file"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.startTime"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.elapsedTime"),
NbBundle.getMessage(this.getClass(),
"IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID")};
private List<IngestManager.IngestThreadActivitySnapshot> snapshots;
private IngestThreadActivitySnapshotsTableModel() {
refresh();
}
private void refresh() {
snapshots = IngestManager.getInstance().getIngestThreadActivitySnapshots();
fireTableDataChanged();
}
@Override
public int getRowCount() {
return snapshots.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
IngestManager.IngestThreadActivitySnapshot snapshot = snapshots.get(rowIndex);
Object cellValue;
switch (columnIndex) {
case 0:
cellValue = snapshot.getThreadId();
break;
case 1:
cellValue = snapshot.getActivity();
break;
case 2:
cellValue = snapshot.getDataSourceName();
break;
case 3:
cellValue = snapshot.getFileName();
break;
case 4:
cellValue = snapshot.getStartTime();
break;
case 5:
Date now = new Date();
long elapsedTime = now.getTime() - snapshot.getStartTime().getTime();
cellValue = DurationFormatUtils.formatDurationHMS(elapsedTime);
break;
case 6:
cellValue = snapshot.getJobId();
break;
default:
cellValue = null;
break;
}
return cellValue;
}
}
private class IngestJobTableModel extends AbstractTableModel {
private final String[] columnNames = {NbBundle.getMessage(this.getClass(), "IngestJobTableModel.colName.jobID"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.dataSource"),
NbBundle.getMessage(this.getClass(), "IngestJobTableModel.colName.start"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.numProcessed"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.filesPerSec"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.inProgress"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.filesQueued"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.dirQueued"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.rootQueued"),
NbBundle.getMessage(this.getClass(),
"IngestJobTableModel.colName.dsQueued")};
private List<DataSourceIngestJob.Snapshot> jobSnapshots;
private IngestJobTableModel() {
refresh();
}
private void refresh() {
jobSnapshots = IngestManager.getInstance().getIngestJobSnapshots();
fireTableDataChanged();
}
@Override
public int getRowCount() {
return jobSnapshots.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
DataSourceIngestJob.Snapshot snapShot = jobSnapshots.get(rowIndex);
Object cellValue;
switch (columnIndex) {
case 0:
cellValue = snapShot.getJobId();
break;
case 1:
cellValue = snapShot.getDataSource();
break;
case 2:
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
cellValue = dateFormat.format(new Date(snapShot.getJobStartTime()));
break;
case 3:
cellValue = snapShot.getFilesProcessed();
break;
case 4:
cellValue = snapShot.getSpeed();
break;
case 5:
cellValue = snapShot.getRunningListSize();
break;
case 6:
cellValue = snapShot.getFileQueueSize();
break;
case 7:
cellValue = snapShot.getDirQueueSize();
break;
case 8:
cellValue = snapShot.getRootQueueSize();
break;
case 9:
cellValue = snapShot.getDsQueueSize();
break;
default:
cellValue = null;
break;
}
return cellValue;
}
}
private class ModuleTableModel extends AbstractTableModel {
private class ModuleStats implements Comparable<ModuleStats> {
private final String name;
private final long duration;
ModuleStats(String name, long duration) {
this.name = name;
this.duration = duration;
}
/**
* @return the name
*/
protected String getName() {
return name;
}
/**
* @return the duration
*/
protected long getDuration() {
return duration;
}
@Override
public int compareTo(ModuleStats o) {
if (duration > o.getDuration()) {
return -1;
} else if (duration == o.getDuration()) {
return 0;
} else {
return 1;
}
}
}
private final String[] columnNames = {NbBundle.getMessage(this.getClass(), "ModuleTableModel.colName.module"),
NbBundle.getMessage(this.getClass(),
"ModuleTableModel.colName.duration")};
private final List<ModuleStats> moduleStats = new ArrayList<>();
private long totalTime;
private ModuleTableModel() {
refresh();
}
private void refresh() {
Map<String, Long> moduleStatMap = IngestManager.getInstance().getModuleRunTimes();
moduleStats.clear();
totalTime = 0;
for (String k : moduleStatMap.keySet()) {
moduleStats.add(new ModuleStats(k, moduleStatMap.get(k)));
totalTime += moduleStatMap.get(k);
}
Collections.sort(moduleStats);
fireTableDataChanged();
}
@Override
public int getRowCount() {
return moduleStats.size();
}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public String getColumnName(int col) {
return columnNames[col];
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
ModuleStats moduleStat = moduleStats.get(rowIndex);
Object cellValue;
switch (columnIndex) {
case 0:
cellValue = moduleStat.getName();
break;
case 1:
cellValue = DurationFormatUtils.formatDurationHMS(moduleStat.getDuration()) + " (" + (moduleStat.getDuration() * 100) / totalTime + "%)";
break;
default:
cellValue = null;
break;
}
return cellValue;
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
snapshotsScrollPane = new javax.swing.JScrollPane();
threadActivitySnapshotsTable = new javax.swing.JTable();
jobScrollPane = new javax.swing.JScrollPane();
jobTable = new javax.swing.JTable();
refreshButton = new javax.swing.JButton();
closeButton = new javax.swing.JButton();
moduleScrollPane = new javax.swing.JScrollPane();
moduleTable = new javax.swing.JTable();
threadActivitySnapshotsTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
snapshotsScrollPane.setViewportView(threadActivitySnapshotsTable);
jobTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
jobScrollPane.setViewportView(jobTable);
org.openide.awt.Mnemonics.setLocalizedText(refreshButton, org.openide.util.NbBundle.getMessage(IngestProgressSnapshotPanel.class, "IngestProgressSnapshotPanel.refreshButton.text")); // NOI18N
refreshButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
refreshButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(IngestProgressSnapshotPanel.class, "IngestProgressSnapshotPanel.closeButton.text")); // NOI18N
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
moduleTable.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
},
new String [] {
}
));
moduleScrollPane.setViewportView(moduleTable);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(snapshotsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 881, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(refreshButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton))
.addComponent(jobScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 881, Short.MAX_VALUE)
.addComponent(moduleScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 881, Short.MAX_VALUE))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, refreshButton});
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(snapshotsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jobScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 102, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(moduleScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 100, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(refreshButton)
.addComponent(closeButton))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {closeButton, refreshButton});
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
parent.dispose();
}//GEN-LAST:event_closeButtonActionPerformed
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
threadActivityTableModel.refresh();
jobTableModel.refresh();
moduleTableModel.refresh();
}//GEN-LAST:event_refreshButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton closeButton;
private javax.swing.JScrollPane jobScrollPane;
private javax.swing.JTable jobTable;
private javax.swing.JScrollPane moduleScrollPane;
private javax.swing.JTable moduleTable;
private javax.swing.JButton refreshButton;
private javax.swing.JScrollPane snapshotsScrollPane;
private javax.swing.JTable threadActivitySnapshotsTable;
// End of variables declaration//GEN-END:variables
}