mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 18:17:43 +00:00
Merge pull request #3078 from sleuthkit/release-4.5.0
Merge in release-4.5.0 branch
This commit is contained in:
commit
15d06c71ca
Binary file not shown.
@ -1,15 +0,0 @@
|
|||||||
<ivy-module version="2.0">
|
|
||||||
<info organisation="org.sleuthkit.autopsy" module="centralrepository"/>
|
|
||||||
<configurations >
|
|
||||||
<!-- module dependencies -->
|
|
||||||
<conf name="central-repository"/>
|
|
||||||
</configurations>
|
|
||||||
<dependencies>
|
|
||||||
<!-- for enterprise artifacts manager -->
|
|
||||||
<dependency conf="central-repository->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
|
|
||||||
<dependency conf="central-repository->default" org="commons-logging" name="commons-logging" rev="1.2"/>
|
|
||||||
<dependency conf="central-repository->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>
|
|
||||||
<dependency conf="central-repository->default" org="org.postgresql" name="postgresql" rev="42.1.1"/>
|
|
||||||
<dependency conf="central-repository->default" org="org.xerial" name="sqlite-jdbc" rev="3.16.1"/>
|
|
||||||
</dependencies>
|
|
||||||
</ivy-module>
|
|
@ -1,10 +0,0 @@
|
|||||||
<ivysettings>
|
|
||||||
<settings defaultResolver="main"/>
|
|
||||||
<resolvers>
|
|
||||||
<chain name="main">
|
|
||||||
<ibiblio name="central" m2compatible="true"/>
|
|
||||||
<ibiblio name="ibiblio" m2compatible="true"/>
|
|
||||||
<ibiblio name="xerial" m2compatible="true" root="http://www.xerial.org/maven/repository/snapshot" />
|
|
||||||
</chain>
|
|
||||||
</resolvers>
|
|
||||||
</ivysettings>
|
|
7
Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
Executable file → Normal file
7
Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
Executable file → Normal file
@ -33,8 +33,6 @@ import java.time.LocalDate;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
|
||||||
import javafx.animation.KeyValue;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -1062,8 +1060,9 @@ public abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an eamArtifact instance to the given known status. If eamArtifact
|
* Sets an eamArtifact instance to the given knownStatus. If eamArtifact
|
||||||
* exists, it is updated. If eamArtifact does not exist nothing happens
|
* exists, it is updated. If eamArtifact does not exist it is added
|
||||||
|
* with the given status.
|
||||||
*
|
*
|
||||||
* @param eamArtifact Artifact containing exactly one (1) ArtifactInstance.
|
* @param eamArtifact Artifact containing exactly one (1) ArtifactInstance.
|
||||||
* @param FileKnown The status to change the artifact to
|
* @param FileKnown The status to change the artifact to
|
||||||
|
@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskDataException;
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
@ -192,4 +193,73 @@ public class EamArtifactUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an EamArtifact from the given Content.
|
||||||
|
* Will return null if an artifact can not be created. Does not
|
||||||
|
* add the artifact to the database.
|
||||||
|
*
|
||||||
|
* @param content The content object
|
||||||
|
* @param knownStatus Unknown, known bad, or known
|
||||||
|
* @param comment The comment for the new artifact (generally used for a tag comment)
|
||||||
|
* @return The new EamArtifact or null if creation failed
|
||||||
|
*/
|
||||||
|
public static EamArtifact getEamArtifactFromContent(Content content, TskData.FileKnown knownStatus, String comment){
|
||||||
|
|
||||||
|
if(! (content instanceof AbstractFile)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AbstractFile af = (AbstractFile) content;
|
||||||
|
|
||||||
|
if ((af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|
||||||
|
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
|
||||||
|
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
|
||||||
|
|| (af.getKnown() == TskData.FileKnown.KNOWN)
|
||||||
|
|| (af.isDir() == true)
|
||||||
|
|| (!af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String dsName;
|
||||||
|
try {
|
||||||
|
dsName = af.getDataSource().getName();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error, unable to get name of data source from abstract file.", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need a hash to make the artifact
|
||||||
|
String md5 = af.getMd5Hash();
|
||||||
|
if (md5 == null || md5.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String deviceId;
|
||||||
|
try {
|
||||||
|
deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(af.getDataSource().getId()).getDeviceId();
|
||||||
|
} catch (TskCoreException | TskDataException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error, failed to get deviceID or data source from current case.", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
EamArtifact eamArtifact;
|
||||||
|
try {
|
||||||
|
EamArtifact.Type filesType = EamDb.getInstance().getCorrelationTypeById(EamArtifact.FILES_TYPE_ID);
|
||||||
|
eamArtifact = new EamArtifact(filesType, af.getMd5Hash());
|
||||||
|
EamArtifactInstance cei = new EamArtifactInstance(
|
||||||
|
new EamCase(Case.getCurrentCase().getName(), Case.getCurrentCase().getDisplayName()),
|
||||||
|
new EamDataSource(deviceId, dsName),
|
||||||
|
af.getParentPath() + af.getName(),
|
||||||
|
comment,
|
||||||
|
TskData.FileKnown.BAD,
|
||||||
|
EamArtifactInstance.GlobalStatus.LOCAL
|
||||||
|
);
|
||||||
|
eamArtifact.addInstance(cei);
|
||||||
|
return eamArtifact;
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error, unable to get FILES correlation type.", ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
50
Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
Executable file → Normal file
50
Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
Executable file → Normal file
@ -30,11 +30,9 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent
|
|||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifact;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifact;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactInstance;
|
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamCase;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamCase;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDataSource;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDataSource;
|
||||||
@ -46,7 +44,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
|||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskDataException;
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
@ -142,57 +139,14 @@ public class CaseEventListener implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|
final EamArtifact eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af,
|
||||||
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
|
knownStatus, comment);
|
||||||
|| (af.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
|
|
||||||
|| (af.getKnown() == TskData.FileKnown.KNOWN)
|
|
||||||
|| (af.isDir() == true)
|
|
||||||
|| (!af.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
String dsName;
|
|
||||||
try {
|
|
||||||
dsName = af.getDataSource().getName();
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error, unable to get name of data source from abstract file during CONTENT_TAG_ADDED event.", ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String md5 = af.getMd5Hash();
|
|
||||||
if (md5 == null || md5.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String deviceId;
|
|
||||||
try {
|
|
||||||
deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(af.getDataSource().getId()).getDeviceId();
|
|
||||||
} catch (TskCoreException | TskDataException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error, failed to get deviceID or data source from current case.", ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EamArtifact eamArtifact;
|
|
||||||
try {
|
|
||||||
EamArtifact.Type filesType = dbManager.getCorrelationTypeById(EamArtifact.FILES_TYPE_ID);
|
|
||||||
eamArtifact = new EamArtifact(filesType, af.getMd5Hash());
|
|
||||||
EamArtifactInstance cei = new EamArtifactInstance(
|
|
||||||
new EamCase(Case.getCurrentCase().getName(), Case.getCurrentCase().getDisplayName()),
|
|
||||||
new EamDataSource(deviceId, dsName),
|
|
||||||
af.getParentPath() + af.getName(),
|
|
||||||
comment,
|
|
||||||
knownStatus,
|
|
||||||
EamArtifactInstance.GlobalStatus.LOCAL
|
|
||||||
);
|
|
||||||
eamArtifact.addInstance(cei);
|
|
||||||
// send update to Central Repository db
|
// send update to Central Repository db
|
||||||
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
|
Runnable r = new KnownStatusChangeRunner(eamArtifact, knownStatus);
|
||||||
// TODO: send r into a thread pool instead
|
// TODO: send r into a thread pool instead
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
t.start();
|
t.start();
|
||||||
} catch (EamDbException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error, unable to get FILES correlation type during CONTENT_TAG_ADDED/CONTENT_TAG_DELETED event.", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
|
} // CONTENT_TAG_ADDED, CONTENT_TAG_DELETED
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.centralrepository.optionspanel;
|
package org.sleuthkit.autopsy.centralrepository.optionspanel;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -27,13 +28,23 @@ import java.util.logging.Level;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.table.DefaultTableModel;
|
import javax.swing.table.DefaultTableModel;
|
||||||
|
import javax.swing.event.TableModelEvent;
|
||||||
|
import javax.swing.event.TableModelListener;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifact;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this class allow a user to select an existing hash database and
|
* Instances of this class allow a user to select an existing hash database and
|
||||||
@ -92,6 +103,8 @@ final class ManageTagsDialog extends javax.swing.JDialog {
|
|||||||
boolean enabled = badTags.contains(tagName);
|
boolean enabled = badTags.contains(tagName);
|
||||||
model.addRow(new Object[]{tagName, enabled});
|
model.addRow(new Object[]{tagName, enabled});
|
||||||
}
|
}
|
||||||
|
CheckBoxModelListener listener = new CheckBoxModelListener(this);
|
||||||
|
model.addTableModelListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display() {
|
private void display() {
|
||||||
@ -231,6 +244,90 @@ final class ManageTagsDialog extends javax.swing.JDialog {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the user sets a tag to "Implies known bad", give them the option to update
|
||||||
|
* any existing tagged items (in the current case only) in the central repo.
|
||||||
|
*/
|
||||||
|
public class CheckBoxModelListener implements TableModelListener {
|
||||||
|
@Messages({"ManageTagsDialog.updateCurrentCase.msg=Mark as known bad any files/artifacts in the current case that have this tag?",
|
||||||
|
"ManageTagsDialog.updateCurrentCase.title=Update current case?",
|
||||||
|
"ManageTagsDialog.updateCurrentCase.error=Error updating existing Central Repository entries"})
|
||||||
|
|
||||||
|
javax.swing.JDialog dialog;
|
||||||
|
public CheckBoxModelListener(javax.swing.JDialog dialog){
|
||||||
|
this.dialog = dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tableChanged(TableModelEvent e) {
|
||||||
|
int row = e.getFirstRow();
|
||||||
|
int column = e.getColumn();
|
||||||
|
if (column == 1) {
|
||||||
|
DefaultTableModel model = (DefaultTableModel) e.getSource();
|
||||||
|
String tagName = (String) model.getValueAt(row, 0);
|
||||||
|
Boolean checked = (Boolean) model.getValueAt(row, column);
|
||||||
|
if (checked) {
|
||||||
|
|
||||||
|
// Don't do anything if there's no case open
|
||||||
|
if(Case.isCaseOpen()){
|
||||||
|
int dialogButton = JOptionPane.YES_NO_OPTION;
|
||||||
|
int dialogResult = JOptionPane.showConfirmDialog (
|
||||||
|
null,
|
||||||
|
Bundle.ManageTagsDialog_updateCurrentCase_msg(),
|
||||||
|
Bundle.ManageTagsDialog_updateCurrentCase_title(),
|
||||||
|
dialogButton);
|
||||||
|
if(dialogResult == JOptionPane.YES_OPTION){
|
||||||
|
try{
|
||||||
|
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
setArtifactsKnownBadByTag(tagName, Case.getCurrentCase());
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to apply known bad status to current case", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, Bundle.ManageTagsDialog_updateCurrentCase_error());
|
||||||
|
} finally {
|
||||||
|
dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set knownBad status for all files/artifacts in the given case that
|
||||||
|
* are tagged with the given tag name.
|
||||||
|
* Files/artifacts that are not already in the database will be added.
|
||||||
|
* @param tagName The name of the tag to search for
|
||||||
|
* @param curCase The case to search in
|
||||||
|
*/
|
||||||
|
public void setArtifactsKnownBadByTag(String tagNameString, Case curCase) throws EamDbException{
|
||||||
|
try{
|
||||||
|
TagName tagName = curCase.getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagNameString);
|
||||||
|
|
||||||
|
// First find any matching artifacts
|
||||||
|
List<BlackboardArtifactTag> artifactTags = curCase.getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
|
||||||
|
|
||||||
|
for(BlackboardArtifactTag bbTag:artifactTags){
|
||||||
|
List<EamArtifact> convertedArtifacts = EamArtifactUtil.fromBlackboardArtifact(bbTag.getArtifact(), true,
|
||||||
|
EamDb.getInstance().getCorrelationTypes(), true);
|
||||||
|
for (EamArtifact eamArtifact : convertedArtifacts) {
|
||||||
|
EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact,TskData.FileKnown.BAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now search for files
|
||||||
|
List<ContentTag> fileTags = curCase.getSleuthkitCase().getContentTagsByTagName(tagName);
|
||||||
|
for(ContentTag contentTag:fileTags){
|
||||||
|
final EamArtifact eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(),
|
||||||
|
TskData.FileKnown.BAD, "");
|
||||||
|
EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, TskData.FileKnown.BAD);
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex){
|
||||||
|
throw new EamDbException("Error updating artifacts", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.ButtonGroup buttonGroup1;
|
private javax.swing.ButtonGroup buttonGroup1;
|
||||||
private javax.swing.JButton cancelButton;
|
private javax.swing.JButton cancelButton;
|
||||||
|
@ -304,6 +304,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
* text box.
|
* text box.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
|
"# {0} - case db status", "# {1} - search svc Status", "# {2} - coord svc Status", "# {3} - msg broker status",
|
||||||
"AutoIngestControlPanel.tbServicesStatusMessage.Message=Case databases {0}, keyword search {1}, coordination {2}, messaging {3} ",
|
"AutoIngestControlPanel.tbServicesStatusMessage.Message=Case databases {0}, keyword search {1}, coordination {2}, messaging {3} ",
|
||||||
"AutoIngestControlPanel.tbServicesStatusMessage.Message.Up=up",
|
"AutoIngestControlPanel.tbServicesStatusMessage.Message.Up=up",
|
||||||
"AutoIngestControlPanel.tbServicesStatusMessage.Message.Down=down",
|
"AutoIngestControlPanel.tbServicesStatusMessage.Message.Down=down",
|
||||||
@ -669,8 +670,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
@Messages({
|
@Messages({
|
||||||
"AutoIngestControlPanel.AutoIngestStartupError=Failed to start automated ingest. Verify Multi-user Settings.",
|
"AutoIngestControlPanel.AutoIngestStartupError=Failed to start automated ingest. Verify Multi-user Settings.",
|
||||||
"AutoIngestControlPanel.AutoIngestStartupFailed.Message=Failed to start automated ingest.\nPlease see auto ingest system log for details.",
|
"AutoIngestControlPanel.AutoIngestStartupFailed.Message=Failed to start automated ingest.\nPlease see auto ingest system log for details.",
|
||||||
"AutoIngestControlPanel.AutoIngestStartupFailed.Title=Automated Ingest Error",
|
"AutoIngestControlPanel.AutoIngestStartupFailed.Title=Automated Ingest Error",})
|
||||||
})
|
|
||||||
private void startUp() {
|
private void startUp() {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -679,7 +679,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
try {
|
try {
|
||||||
manager.startUp();
|
manager.startUp();
|
||||||
autoIngestStarted = true;
|
autoIngestStarted = true;
|
||||||
} catch (AutoIngestManager.AutoIngestManagerStartupException ex) {
|
} catch (AutoIngestManager.AutoIngestManagerException ex) {
|
||||||
SYS_LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex);
|
SYS_LOGGER.log(Level.SEVERE, "Dashboard error starting up auto ingest", ex);
|
||||||
tbStatusMessage.setText(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.AutoIngestStartupError"));
|
tbStatusMessage.setText(NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.AutoIngestStartupError"));
|
||||||
manager = null;
|
manager = null;
|
||||||
@ -812,8 +812,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
"AutoIngestControlPanel.PauseDueToWriteStateFilesFailure=Paused, unable to write to shared images or cases location.",
|
"AutoIngestControlPanel.PauseDueToWriteStateFilesFailure=Paused, unable to write to shared images or cases location.",
|
||||||
"AutoIngestControlPanel.PauseDueToSharedConfigError=Paused, unable to update shared configuration.",
|
"AutoIngestControlPanel.PauseDueToSharedConfigError=Paused, unable to update shared configuration.",
|
||||||
"AutoIngestControlPanel.PauseDueToIngestJobStartFailure=Paused, unable to start ingest job processing.",
|
"AutoIngestControlPanel.PauseDueToIngestJobStartFailure=Paused, unable to start ingest job processing.",
|
||||||
"AutoIngestControlPanel.PauseDueToFileExporterError=Paused, unable to load File Exporter settings.",
|
"AutoIngestControlPanel.PauseDueToFileExporterError=Paused, unable to load File Exporter settings.",})
|
||||||
})
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
|
|
||||||
@ -983,7 +982,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
List<AutoIngestJob> completedJobs = new ArrayList<>();
|
List<AutoIngestJob> completedJobs = new ArrayList<>();
|
||||||
manager.getJobs(pendingJobs, runningJobs, completedJobs);
|
manager.getJobs(pendingJobs, runningJobs, completedJobs);
|
||||||
// Sort the completed jobs list by completed date
|
// Sort the completed jobs list by completed date
|
||||||
Collections.sort(completedJobs, new AutoIngestJob.ReverseDateCompletedComparator());
|
Collections.sort(completedJobs, new AutoIngestJob.ReverseCompletedDateComparator());
|
||||||
EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs));
|
EventQueue.invokeLater(new RefreshComponentsTask(pendingJobs, runningJobs, completedJobs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1076,7 +1075,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
* @return True or fale.
|
* @return True or fale.
|
||||||
*/
|
*/
|
||||||
private boolean isLocalJob(AutoIngestJob job) {
|
private boolean isLocalJob(AutoIngestJob job) {
|
||||||
return job.getNodeName().equals(LOCAL_HOST_NAME);
|
return job.getProcessingHostName().equals(LOCAL_HOST_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1145,20 +1144,19 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
tableModel.setRowCount(0);
|
tableModel.setRowCount(0);
|
||||||
for (AutoIngestJob job : jobs) {
|
for (AutoIngestJob job : jobs) {
|
||||||
AutoIngestJob.StageDetails status = job.getStageDetails();
|
AutoIngestJob.StageDetails status = job.getStageDetails();
|
||||||
AutoIngestJobNodeData nodeData = job.getNodeData();
|
|
||||||
tableModel.addRow(new Object[]{
|
tableModel.addRow(new Object[]{
|
||||||
nodeData.getCaseName(), // CASE
|
job.getManifest().getCaseName(), // CASE
|
||||||
nodeData.getDataSourcePath().getFileName(), // DATA_SOURCE
|
job.getManifest().getDataSourcePath().getFileName(), // DATA_SOURCE
|
||||||
job.getNodeName(), // HOST_NAME
|
job.getProcessingHostName(), // HOST_NAME
|
||||||
nodeData.getManifestFileDate(), // CREATED_TIME
|
job.getManifest().getDateFileCreated(), // CREATED_TIME
|
||||||
job.getStageStartDate(), // STARTED_TIME
|
job.getProcessingStageStartDate(), // STARTED_TIME
|
||||||
nodeData.getCompletedDate(), // COMPLETED_TIME
|
job.getCompletedDate(), // COMPLETED_TIME
|
||||||
status.getDescription(), // ACTIVITY
|
status.getDescription(), // ACTIVITY
|
||||||
nodeData.getErrorsOccurred(), // STATUS
|
job.getErrorsOccurred(), // STATUS
|
||||||
((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME
|
((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME
|
||||||
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
|
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
|
||||||
job.getNodeName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB
|
job.getProcessingHostName().equals(LOCAL_HOST_NAME), // IS_LOCAL_JOB
|
||||||
nodeData.getManifestFilePath()}); // MANIFEST_FILE_PATH
|
job.getManifest().getFilePath()}); // MANIFEST_FILE_PATH
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex);
|
SYS_LOGGER.log(Level.SEVERE, "Dashboard error refreshing table", ex);
|
||||||
@ -1703,11 +1701,17 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
*
|
*
|
||||||
* @param evt The button click event.
|
* @param evt The button click event.
|
||||||
*/
|
*/
|
||||||
|
@Messages({"AutoIngestControlPanel.casePrioritization.errorMessage=An error occurred when prioritizing the case. Some or all jobs may not have been prioritized."})
|
||||||
private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed
|
private void bnPrioritizeCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeCaseActionPerformed
|
||||||
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
|
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
|
||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString();
|
String caseName = (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.CASE.ordinal())).toString();
|
||||||
|
try {
|
||||||
manager.prioritizeCase(caseName);
|
manager.prioritizeCase(caseName);
|
||||||
|
} catch (AutoIngestManager.AutoIngestManagerException ex) {
|
||||||
|
SYS_LOGGER.log(Level.SEVERE, "Error prioritizing a case", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.AutoIngestControlPanel_casePrioritization_errorMessage());
|
||||||
|
}
|
||||||
refreshTables();
|
refreshTables();
|
||||||
pendingTable.clearSelection();
|
pendingTable.clearSelection();
|
||||||
enablePendingTableButtons(false);
|
enablePendingTableButtons(false);
|
||||||
@ -1756,11 +1760,17 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
}
|
}
|
||||||
}//GEN-LAST:event_bnShowCaseLogActionPerformed
|
}//GEN-LAST:event_bnShowCaseLogActionPerformed
|
||||||
|
|
||||||
|
@Messages({"AutoIngestControlPanel.jobPrioritization.errorMessage=An error occurred when prioritizing the job."})
|
||||||
private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed
|
private void bnPrioritizeJobActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnPrioritizeJobActionPerformed
|
||||||
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
|
if (pendingTableModel.getRowCount() > 0 && pendingTable.getSelectedRow() >= 0) {
|
||||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()));
|
Path manifestFilePath = (Path) (pendingTableModel.getValueAt(pendingTable.getSelectedRow(), JobsTableModelColumns.MANIFEST_FILE_PATH.ordinal()));
|
||||||
|
try {
|
||||||
manager.prioritizeJob(manifestFilePath);
|
manager.prioritizeJob(manifestFilePath);
|
||||||
|
} catch (AutoIngestManager.AutoIngestManagerException ex) {
|
||||||
|
SYS_LOGGER.log(Level.SEVERE, "Error prioritizing a case", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.AutoIngestControlPanel_jobPrioritization_errorMessage());
|
||||||
|
}
|
||||||
refreshTables();
|
refreshTables();
|
||||||
pendingTable.clearSelection();
|
pendingTable.clearSelection();
|
||||||
enablePendingTableButtons(false);
|
enablePendingTableButtons(false);
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Component class="javax.swing.JButton" name="jButton1">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="AutoIngestDashboard.jButton1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</NonVisualComponents>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
@ -41,7 +50,7 @@
|
|||||||
<Component id="runningScrollPane" alignment="0" max="32767" attributes="0"/>
|
<Component id="runningScrollPane" alignment="0" max="32767" attributes="0"/>
|
||||||
<Component id="completedScrollPane" alignment="0" max="32767" attributes="0"/>
|
<Component id="completedScrollPane" alignment="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
|
@ -31,7 +31,6 @@ import java.util.logging.Level;
|
|||||||
import javax.swing.DefaultListSelectionModel;
|
import javax.swing.DefaultListSelectionModel;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.util.Collections;
|
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
@ -438,11 +437,9 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
List<AutoIngestJob> pendingJobs = jobsSnapshot.getPendingJobs();
|
List<AutoIngestJob> pendingJobs = jobsSnapshot.getPendingJobs();
|
||||||
List<AutoIngestJob> runningJobs = jobsSnapshot.getRunningJobs();
|
List<AutoIngestJob> runningJobs = jobsSnapshot.getRunningJobs();
|
||||||
List<AutoIngestJob> completedJobs = jobsSnapshot.getCompletedJobs();
|
List<AutoIngestJob> completedJobs = jobsSnapshot.getCompletedJobs();
|
||||||
|
pendingJobs.sort(new AutoIngestJob.PriorityComparator());
|
||||||
// DLG: DONE! Do the appropriate sorts for each table.
|
runningJobs.sort(new AutoIngestJob.CaseNameAndProcessingHostComparator());
|
||||||
Collections.sort(pendingJobs, new AutoIngestJob.PriorityComparator());
|
completedJobs.sort(new AutoIngestJob.ReverseCompletedDateComparator());
|
||||||
runningJobs.sort(new AutoIngestJob.AlphabeticalComparator());
|
|
||||||
|
|
||||||
refreshTable(pendingJobs, pendingTable, pendingTableModel);
|
refreshTable(pendingJobs, pendingTable, pendingTableModel);
|
||||||
refreshTable(runningJobs, runningTable, runningTableModel);
|
refreshTable(runningJobs, runningTable, runningTableModel);
|
||||||
refreshTable(completedJobs, completedTable, completedTableModel);
|
refreshTable(completedJobs, completedTable, completedTableModel);
|
||||||
@ -462,27 +459,25 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
Path currentRow = getSelectedEntry(table, tableModel);
|
Path currentRow = getSelectedEntry(table, tableModel);
|
||||||
tableModel.setRowCount(0);
|
tableModel.setRowCount(0);
|
||||||
for (AutoIngestJob job : jobs) {
|
for (AutoIngestJob job : jobs) {
|
||||||
if (job.getNodeData().getVersion() < 1) {
|
if (job.getVersion() < 1) {
|
||||||
// Ignore version '0' nodes since they don't carry enough
|
// Ignore version '0' nodes since they don't carry enough
|
||||||
// data to populate the table.
|
// data to populate the table.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AutoIngestJob.StageDetails status = job.getStageDetails();
|
AutoIngestJob.StageDetails status = job.getStageDetails();
|
||||||
AutoIngestJobNodeData nodeData = job.getNodeData();
|
|
||||||
tableModel.addRow(new Object[]{
|
tableModel.addRow(new Object[]{
|
||||||
nodeData.getCaseName(), // CASE
|
job.getManifest().getCaseName(), // CASE
|
||||||
nodeData.getDataSourcePath().getFileName(), // DATA_SOURCE
|
job.getManifest().getDataSourcePath().getFileName(), job.getProcessingHostName(), // HOST_NAME
|
||||||
job.getNodeName(), // HOST_NAME
|
job.getManifest().getDateFileCreated(), // CREATED_TIME
|
||||||
nodeData.getManifestFileDate(), // CREATED_TIME
|
job.getProcessingStageStartDate(), // STARTED_TIME
|
||||||
job.getStageStartDate(), // STARTED_TIME
|
job.getCompletedDate(), // COMPLETED_TIME
|
||||||
nodeData.getCompletedDate(), // COMPLETED_TIME
|
|
||||||
status.getDescription(), // ACTIVITY
|
status.getDescription(), // ACTIVITY
|
||||||
nodeData.getErrorsOccurred(), // STATUS
|
job.getErrorsOccurred(), // STATUS
|
||||||
((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME
|
((Date.from(Instant.now()).getTime()) - (status.getStartDate().getTime())), // ACTIVITY_TIME
|
||||||
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
|
job.getCaseDirectoryPath(), // CASE_DIRECTORY_PATH
|
||||||
nodeData.getManifestFilePath()//DLG: , // MANIFEST_FILE_PATH
|
job.getManifest().getFilePath() // MANIFEST_FILE_PATH
|
||||||
//DLG: job
|
//DLG: Put job object in the table
|
||||||
}); // JOB
|
});
|
||||||
}
|
}
|
||||||
setSelectedEntry(table, tableModel, currentRow);
|
setSelectedEntry(table, tableModel, currentRow);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
@ -547,7 +542,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
*/
|
*/
|
||||||
private enum JobsTableModelColumns {
|
private enum JobsTableModelColumns {
|
||||||
|
|
||||||
// DLG: Go through the bundles.properties file and delete any unused key-value pairs.
|
// DLG: Go through the bundle.properties file and delete any unused key-value pairs.
|
||||||
CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")),
|
CASE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.Case")),
|
||||||
DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")),
|
DATA_SOURCE(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.ImageFolder")),
|
||||||
HOST_NAME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")),
|
HOST_NAME(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.JobsTableModel.ColumnHeader.HostName")),
|
||||||
@ -662,6 +657,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
|
jButton1 = new javax.swing.JButton();
|
||||||
pendingScrollPane = new javax.swing.JScrollPane();
|
pendingScrollPane = new javax.swing.JScrollPane();
|
||||||
pendingTable = new javax.swing.JTable();
|
pendingTable = new javax.swing.JTable();
|
||||||
runningScrollPane = new javax.swing.JScrollPane();
|
runningScrollPane = new javax.swing.JScrollPane();
|
||||||
@ -676,6 +672,8 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
tbServicesStatusMessage = new javax.swing.JTextField();
|
tbServicesStatusMessage = new javax.swing.JTextField();
|
||||||
prioritizeButton = new javax.swing.JButton();
|
prioritizeButton = new javax.swing.JButton();
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.jButton1.text")); // NOI18N
|
||||||
|
|
||||||
pendingTable.setModel(pendingTableModel);
|
pendingTable.setModel(pendingTableModel);
|
||||||
pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N
|
pendingTable.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.pendingTable.toolTipText")); // NOI18N
|
||||||
pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
|
pendingTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||||
@ -843,8 +841,6 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
jobsSnapshot = autoIngestMonitor.prioritizeJob(manifestFilePath);
|
jobsSnapshot = autoIngestMonitor.prioritizeJob(manifestFilePath);
|
||||||
refreshTables(jobsSnapshot);
|
refreshTables(jobsSnapshot);
|
||||||
} catch (AutoIngestMonitor.AutoIngestMonitorException ex) {
|
} catch (AutoIngestMonitor.AutoIngestMonitorException ex) {
|
||||||
// DLG: DONE! Log the exception and do a popup with a user-friendly
|
|
||||||
// message explaining that the operation failed
|
|
||||||
String errorMessage = String.format(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.PrioritizeError"), manifestFilePath);
|
String errorMessage = String.format(NbBundle.getMessage(AutoIngestDashboard.class, "AutoIngestDashboard.PrioritizeError"), manifestFilePath);
|
||||||
logger.log(Level.SEVERE, errorMessage, ex);
|
logger.log(Level.SEVERE, errorMessage, ex);
|
||||||
MessageNotifyUtil.Message.error(errorMessage);
|
MessageNotifyUtil.Message.error(errorMessage);
|
||||||
@ -856,6 +852,7 @@ public final class AutoIngestDashboard extends JPanel implements Observer {
|
|||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JScrollPane completedScrollPane;
|
private javax.swing.JScrollPane completedScrollPane;
|
||||||
private javax.swing.JTable completedTable;
|
private javax.swing.JTable completedTable;
|
||||||
|
private javax.swing.JButton jButton1;
|
||||||
private javax.swing.JLabel lbCompleted;
|
private javax.swing.JLabel lbCompleted;
|
||||||
private javax.swing.JLabel lbPending;
|
private javax.swing.JLabel lbPending;
|
||||||
private javax.swing.JLabel lbRunning;
|
private javax.swing.JLabel lbRunning;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2015-2017 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -22,6 +22,7 @@ import java.io.Serializable;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -40,23 +41,63 @@ import org.sleuthkit.autopsy.ingest.IngestJob;
|
|||||||
public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
|
public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final int CURRENT_VERSION = 1;
|
||||||
|
private static final int DEFAULT_PRIORITY = 0;
|
||||||
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
|
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
|
||||||
private final AutoIngestJobNodeData nodeData;
|
private final int version;
|
||||||
|
private final Manifest manifest;
|
||||||
private final String nodeName;
|
private final String nodeName;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private String caseDirectoryPath; // DLG: Replace with AutoIngestJobNodeData.caseDirectoryPath
|
private String caseDirectoryPath;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private Integer priority;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
private Date stageStartDate;
|
private Date stageStartDate;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
|
private StageDetails stageDetails;
|
||||||
|
@GuardedBy("this")
|
||||||
transient private DataSourceProcessor dataSourceProcessor;
|
transient private DataSourceProcessor dataSourceProcessor;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
transient private IngestJob ingestJob;
|
transient private IngestJob ingestJob;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
transient private boolean canceled;
|
transient private boolean cancelled;
|
||||||
@GuardedBy("this")
|
@GuardedBy("this")
|
||||||
transient private boolean completed;
|
transient private boolean completed;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private Date completedDate;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private boolean errorsOccurred;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private ProcessingStatus processingStatus;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private int numberOfCrashes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new automated ingest job for a manifest. All job state not
|
||||||
|
* specified in the manifest is set to the default state for a new job.
|
||||||
|
*
|
||||||
|
* @param manifest The manifest.
|
||||||
|
*/
|
||||||
|
AutoIngestJob(Manifest manifest) {
|
||||||
|
this.version = CURRENT_VERSION;
|
||||||
|
this.manifest = manifest;
|
||||||
|
this.nodeName = AutoIngestJob.LOCAL_HOST_NAME;
|
||||||
|
this.caseDirectoryPath = "";
|
||||||
|
this.priority = DEFAULT_PRIORITY;
|
||||||
|
this.stage = Stage.PENDING;
|
||||||
|
this.stageStartDate = manifest.getDateFileCreated();
|
||||||
|
this.stageDetails = this.getStageDetails();
|
||||||
|
this.dataSourceProcessor = null;
|
||||||
|
this.ingestJob = null;
|
||||||
|
this.cancelled = false;
|
||||||
|
this.completed = false;
|
||||||
|
this.completedDate = new Date(0);
|
||||||
|
this.errorsOccurred = false;
|
||||||
|
this.processingStatus = ProcessingStatus.PENDING;
|
||||||
|
this.numberOfCrashes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an automated ingest job for a manifest. The manifest specifies
|
* Constructs an automated ingest job for a manifest. The manifest specifies
|
||||||
@ -67,48 +108,33 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
* AutoIngestJob class.
|
* AutoIngestJob class.
|
||||||
*
|
*
|
||||||
* @param nodeData The node data.
|
* @param nodeData The node data.
|
||||||
* @param caseDirectoryPath The path to the case directory for the job, may
|
|
||||||
* be null.
|
|
||||||
* @param nodeName If the job is in progress, the node doing the
|
|
||||||
* processing, otherwise the locla host.
|
|
||||||
* @param stage The processing stage for display purposes.
|
|
||||||
*/
|
*/
|
||||||
/*
|
AutoIngestJob(AutoIngestJobNodeData nodeData) {
|
||||||
* DLG: We need a contrucotr that takes just the node data. When we have
|
this.version = nodeData.getVersion();
|
||||||
* added the case dierectory path, the host name and the stage data to the
|
this.manifest = new Manifest(nodeData.getManifestFilePath(), nodeData.getManifestFileDate(), nodeData.getCaseName(), nodeData.getDeviceId(), nodeData.getDataSourcePath(), Collections.emptyMap());
|
||||||
* ZK nodes, we probably cna use that constructor only. I'm thinking this
|
this.nodeName = nodeData.getProcessingHostName();
|
||||||
* because we will creater node data with initial values when we first
|
this.caseDirectoryPath = nodeData.getCaseDirectoryPath().toString();
|
||||||
* discover the nodes, and then we will continue to update it.
|
this.priority = nodeData.getPriority();
|
||||||
*/
|
this.stage = nodeData.getProcessingStage();
|
||||||
AutoIngestJob(AutoIngestJobNodeData nodeData, Path caseDirectoryPath, String nodeName, Stage stage) {
|
this.stageStartDate = nodeData.getProcessingStageStartDate();
|
||||||
this.nodeData = nodeData;
|
this.stageDetails = this.getStageDetails();
|
||||||
if (null != caseDirectoryPath) {
|
this.dataSourceProcessor = null;
|
||||||
this.caseDirectoryPath = caseDirectoryPath.toString();
|
this.ingestJob = null;
|
||||||
} else {
|
this.cancelled = false;
|
||||||
this.caseDirectoryPath = "";
|
this.completed = false;
|
||||||
}
|
this.completedDate = nodeData.getCompletedDate();
|
||||||
this.nodeName = nodeName;
|
this.errorsOccurred = nodeData.getErrorsOccurred();
|
||||||
this.stage = stage;
|
this.processingStatus = nodeData.getProcessingStatus();
|
||||||
this.stageStartDate = nodeData.getManifestFileDate();
|
this.numberOfCrashes = nodeData.getNumberOfCrashes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the auto ingest job node data.
|
* Gets the auto ingest job manifest.
|
||||||
*
|
*
|
||||||
* @return The node data.
|
* @return The manifest.
|
||||||
*/
|
*/
|
||||||
AutoIngestJobNodeData getNodeData() {
|
Manifest getManifest() {
|
||||||
return this.nodeData;
|
return this.manifest;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries whether or not a case directory path has been set for this auto
|
|
||||||
* ingest job.
|
|
||||||
*
|
|
||||||
* @return True or false
|
|
||||||
*/
|
|
||||||
synchronized boolean hasCaseDirectoryPath() {
|
|
||||||
return (false == this.caseDirectoryPath.isEmpty());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,30 +161,46 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setStage(Stage newStage) {
|
/**
|
||||||
setStage(newStage, Date.from(Instant.now()));
|
* Sets the priority of the job. A higher number indicates a higher
|
||||||
|
* priority.
|
||||||
|
*
|
||||||
|
* @param priority The priority.
|
||||||
|
*/
|
||||||
|
synchronized void setPriority(Integer priority) {
|
||||||
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setStage(Stage newState, Date stateStartedDate) {
|
/**
|
||||||
if (Stage.CANCELING == this.stage && Stage.COMPLETED != newState) {
|
* Gets the priority of the job. A higher number indicates a higher
|
||||||
|
* priority.
|
||||||
|
*
|
||||||
|
* @return The priority.
|
||||||
|
*/
|
||||||
|
synchronized Integer getPriority() {
|
||||||
|
return this.priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setStage(Stage newStage) {
|
||||||
|
if (Stage.CANCELLING == this.stage && Stage.COMPLETED != newStage) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.stage = newState;
|
this.stage = newStage;
|
||||||
this.stageStartDate = stateStartedDate;
|
this.stageStartDate = Date.from(Instant.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized Stage getStage() {
|
synchronized Stage getProcessingStage() {
|
||||||
return this.stage;
|
return this.stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized Date getStageStartDate() {
|
synchronized Date getProcessingStageStartDate() {
|
||||||
return this.stageStartDate;
|
return new Date(this.stageStartDate.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized StageDetails getStageDetails() {
|
synchronized StageDetails getStageDetails() {
|
||||||
String description;
|
String description;
|
||||||
Date startDate;
|
Date startDate;
|
||||||
if (Stage.CANCELING != this.stage && null != this.ingestJob) {
|
if (Stage.CANCELLING != this.stage && null != this.ingestJob) {
|
||||||
IngestJob.ProgressSnapshot progress = this.ingestJob.getSnapshot();
|
IngestJob.ProgressSnapshot progress = this.ingestJob.getSnapshot();
|
||||||
IngestJob.DataSourceIngestModuleHandle ingestModuleHandle = progress.runningDataSourceIngestModule();
|
IngestJob.DataSourceIngestModuleHandle ingestModuleHandle = progress.runningDataSourceIngestModule();
|
||||||
if (null != ingestModuleHandle) {
|
if (null != ingestModuleHandle) {
|
||||||
@ -171,7 +213,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
if (!ingestModuleHandle.isCancelled()) {
|
if (!ingestModuleHandle.isCancelled()) {
|
||||||
description = ingestModuleHandle.displayName();
|
description = ingestModuleHandle.displayName();
|
||||||
} else {
|
} else {
|
||||||
description = String.format(Stage.CANCELING_MODULE.getDisplayText(), ingestModuleHandle.displayName());
|
description = String.format(Stage.CANCELLING_MODULE.getDisplayText(), ingestModuleHandle.displayName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/**
|
/**
|
||||||
@ -189,7 +231,12 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
description = this.stage.getDisplayText();
|
description = this.stage.getDisplayText();
|
||||||
startDate = this.stageStartDate;
|
startDate = this.stageStartDate;
|
||||||
}
|
}
|
||||||
return new StageDetails(description, startDate);
|
this.stageDetails = new StageDetails(description, startDate);
|
||||||
|
return this.stageDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setStageDetails(StageDetails stageDetails) {
|
||||||
|
this.stageDetails = stageDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setDataSourceProcessor(DataSourceProcessor dataSourceProcessor) {
|
synchronized void setDataSourceProcessor(DataSourceProcessor dataSourceProcessor) {
|
||||||
@ -205,9 +252,9 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
}
|
}
|
||||||
|
|
||||||
synchronized void cancel() {
|
synchronized void cancel() {
|
||||||
setStage(Stage.CANCELING);
|
setStage(Stage.CANCELLING);
|
||||||
canceled = true;
|
cancelled = true;
|
||||||
nodeData.setErrorsOccurred(true);
|
errorsOccurred = true;
|
||||||
if (null != dataSourceProcessor) {
|
if (null != dataSourceProcessor) {
|
||||||
dataSourceProcessor.cancel();
|
dataSourceProcessor.cancel();
|
||||||
}
|
}
|
||||||
@ -217,7 +264,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean isCanceled() {
|
synchronized boolean isCanceled() {
|
||||||
return canceled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setCompleted() {
|
synchronized void setCompleted() {
|
||||||
@ -229,10 +276,68 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
return completed;
|
return completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getNodeName() {
|
/**
|
||||||
|
* Sets the date the job was completed, with or without cancellation or
|
||||||
|
* errors.
|
||||||
|
*
|
||||||
|
* @param completedDate The completion date.
|
||||||
|
*/
|
||||||
|
synchronized void setCompletedDate(Date completedDate) {
|
||||||
|
this.completedDate = new Date(completedDate.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the date the job was completed, with or without cancellation or
|
||||||
|
* errors.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
synchronized Date getCompletedDate() {
|
||||||
|
return new Date(completedDate.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not errors occurred during the processing of the job.
|
||||||
|
*
|
||||||
|
* @param errorsOccurred True or false;
|
||||||
|
*/
|
||||||
|
synchronized void setErrorsOccurred(boolean errorsOccurred) {
|
||||||
|
this.errorsOccurred = errorsOccurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries whether or not errors occurred during the processing of the job.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
synchronized boolean getErrorsOccurred() {
|
||||||
|
return this.errorsOccurred;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized String getProcessingHostName() {
|
||||||
return nodeName;
|
return nodeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getVersion() {
|
||||||
|
return this.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized ProcessingStatus getProcessingStatus() {
|
||||||
|
return this.processingStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setProcessingStatus(ProcessingStatus processingStatus) {
|
||||||
|
this.processingStatus = processingStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized int getNumberOfCrashes() {
|
||||||
|
return this.numberOfCrashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized void setNumberOfCrashes(int numberOfCrashes) {
|
||||||
|
this.numberOfCrashes = numberOfCrashes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (!(obj instanceof AutoIngestJob)) {
|
if (!(obj instanceof AutoIngestJob)) {
|
||||||
@ -241,11 +346,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
if (obj == this) {
|
if (obj == this) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return this.getManifest().getFilePath().equals(((AutoIngestJob) obj).getManifest().getFilePath());
|
||||||
Path manifestPath1 = this.getNodeData().getManifestFilePath();
|
|
||||||
Path manifestPath2 = ((AutoIngestJob) obj).getNodeData().getManifestFilePath();
|
|
||||||
|
|
||||||
return manifestPath1.equals(manifestPath2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -256,29 +357,20 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(AutoIngestJob o) {
|
public int compareTo(AutoIngestJob o) {
|
||||||
Date date1 = this.getNodeData().getManifestFileDate();
|
return -this.getManifest().getDateFileCreated().compareTo(o.getManifest().getDateFileCreated());
|
||||||
Date date2 = o.getNodeData().getManifestFileDate();
|
|
||||||
|
|
||||||
return -date1.compareTo(date2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DLG: Add a toString override
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
// DLG: FINISH ME!
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom comparator that allows us to sort List<AutoIngestJob> on reverse
|
* Custom comparator that allows us to sort List<AutoIngestJob> on reverse
|
||||||
* chronological date modified (descending)
|
* chronological date modified (descending)
|
||||||
*/
|
*/
|
||||||
static class ReverseDateCompletedComparator implements Comparator<AutoIngestJob> {
|
static class ReverseCompletedDateComparator implements Comparator<AutoIngestJob> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(AutoIngestJob o1, AutoIngestJob o2) {
|
public int compare(AutoIngestJob o1, AutoIngestJob o2) {
|
||||||
return -o1.getStageStartDate().compareTo(o2.getStageStartDate());
|
return -o1.getCompletedDate().compareTo(o2.getCompletedDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -288,10 +380,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(AutoIngestJob job, AutoIngestJob anotherJob) {
|
public int compare(AutoIngestJob job, AutoIngestJob anotherJob) {
|
||||||
Integer priority1 = job.getNodeData().getPriority();
|
return -(job.getPriority().compareTo(anotherJob.getPriority()));
|
||||||
Integer priority2 = anotherJob.getNodeData().getPriority();
|
|
||||||
|
|
||||||
return -priority1.compareTo(priority2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -301,21 +390,29 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
* alphabetically except for jobs for the current host, which are placed at
|
* alphabetically except for jobs for the current host, which are placed at
|
||||||
* the top of the list.
|
* the top of the list.
|
||||||
*/
|
*/
|
||||||
static class AlphabeticalComparator implements Comparator<AutoIngestJob> {
|
static class CaseNameAndProcessingHostComparator implements Comparator<AutoIngestJob> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(AutoIngestJob o1, AutoIngestJob o2) {
|
public int compare(AutoIngestJob o1, AutoIngestJob o2) {
|
||||||
if (o1.getNodeName().equalsIgnoreCase(LOCAL_HOST_NAME)) {
|
if (o1.getProcessingHostName().equalsIgnoreCase(LOCAL_HOST_NAME)) {
|
||||||
return -1; // o1 is for current case, float to top
|
return -1; // o1 is for current case, float to top
|
||||||
} else if (o2.getNodeName().equalsIgnoreCase(LOCAL_HOST_NAME)) {
|
} else if (o2.getProcessingHostName().equalsIgnoreCase(LOCAL_HOST_NAME)) {
|
||||||
return 1; // o2 is for current case, float to top
|
return 1; // o2 is for current case, float to top
|
||||||
} else {
|
} else {
|
||||||
String caseName1 = o1.getNodeData().getCaseName();
|
return o1.getManifest().getCaseName().compareToIgnoreCase(o2.getManifest().getCaseName());
|
||||||
String caseName2 = o2.getNodeData().getCaseName();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return caseName1.compareToIgnoreCase(caseName2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processing status for the auto ingest job for the manifest.
|
||||||
|
*/
|
||||||
|
enum ProcessingStatus {
|
||||||
|
PENDING,
|
||||||
|
PROCESSING,
|
||||||
|
COMPLETED,
|
||||||
|
DELETED
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Stage {
|
enum Stage {
|
||||||
@ -330,8 +427,8 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
ANALYZING_DATA_SOURCE("Analyzing data source"),
|
ANALYZING_DATA_SOURCE("Analyzing data source"),
|
||||||
ANALYZING_FILES("Analyzing files"),
|
ANALYZING_FILES("Analyzing files"),
|
||||||
EXPORTING_FILES("Exporting files"),
|
EXPORTING_FILES("Exporting files"),
|
||||||
CANCELING_MODULE("Canceling module"),
|
CANCELLING_MODULE("Cancelling module"),
|
||||||
CANCELING("Canceling"),
|
CANCELLING("Cancelling"),
|
||||||
COMPLETED("Completed");
|
COMPLETED("Completed");
|
||||||
|
|
||||||
private final String displayText;
|
private final String displayText;
|
||||||
@ -347,12 +444,13 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
static final class StageDetails {
|
static final class StageDetails implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
private final String description;
|
private final String description;
|
||||||
private final Date startDate;
|
private final Date startDate;
|
||||||
|
|
||||||
private StageDetails(String description, Date startDate) {
|
StageDetails(String description, Date startDate) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.startDate = startDate;
|
this.startDate = startDate;
|
||||||
}
|
}
|
||||||
@ -362,7 +460,7 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
|
|||||||
}
|
}
|
||||||
|
|
||||||
Date getStartDate() {
|
Date getStartDate() {
|
||||||
return this.startDate;
|
return new Date(this.startDate.getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@ -26,20 +26,19 @@ import java.util.Date;
|
|||||||
import javax.lang.model.type.TypeKind;
|
import javax.lang.model.type.TypeKind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A coordination service node data transfer object for an auto ingest job.
|
* An object that converts auto ingest job data for an auto ingest job
|
||||||
|
* coordination service node to and from byte arrays.
|
||||||
*/
|
*/
|
||||||
final class AutoIngestJobNodeData implements Serializable {
|
final class AutoIngestJobNodeData {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final int CURRENT_VERSION = 1;
|
||||||
private static final int NODE_DATA_VERSION = 1;
|
private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131629;
|
||||||
private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131493;
|
|
||||||
private static final int DEFAULT_PRIORITY = 0;
|
private static final int DEFAULT_PRIORITY = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Version 0 fields.
|
* Version 0 fields.
|
||||||
*/
|
*/
|
||||||
private final boolean coordSvcNodeDataWasSet;
|
private int processingStatus;
|
||||||
private ProcessingStatus status;
|
|
||||||
private int priority;
|
private int priority;
|
||||||
private int numberOfCrashes;
|
private int numberOfCrashes;
|
||||||
private long completedDate;
|
private long completedDate;
|
||||||
@ -49,228 +48,197 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
* Version 1 fields.
|
* Version 1 fields.
|
||||||
*/
|
*/
|
||||||
private int version;
|
private int version;
|
||||||
private String deviceId;
|
|
||||||
private String caseName;
|
|
||||||
private String caseDirectoryPath;
|
|
||||||
private long manifestFileDate;
|
|
||||||
private String manifestFilePath;
|
private String manifestFilePath;
|
||||||
|
private long manifestFileDate;
|
||||||
|
private String caseName;
|
||||||
|
private String deviceId;
|
||||||
private String dataSourcePath;
|
private String dataSourcePath;
|
||||||
private String processingStage;
|
private String caseDirectoryPath;
|
||||||
|
private String processingHostName;
|
||||||
|
private byte processingStage;
|
||||||
private long processingStageStartDate;
|
private long processingStageStartDate;
|
||||||
private String processingHost;
|
private String processingStageDetailsDescription;
|
||||||
|
private long processingStageDetailsStartDate;
|
||||||
|
|
||||||
//DLG: Add caseDirectoryPath from AutoIngestJob
|
|
||||||
/*
|
|
||||||
* DLG: Rename class to AutoIngestJobNodeData - Add String
|
|
||||||
* caseDirectoryPath. Needed to locate case auto ingest log and later, for
|
|
||||||
* case deletion
|
|
||||||
*
|
|
||||||
* Add String processingStage, long processingStageStartDate, String
|
|
||||||
* processingHost fields. These three fields are needed to populate running
|
|
||||||
* jobs table; use of auto ingest job data is not enough, because there
|
|
||||||
* would be no data until a status event was received by the auto ingest
|
|
||||||
* monitor.
|
|
||||||
*
|
|
||||||
* Update the AutoIngestManager code that creates ZK nodes for auto ingest
|
|
||||||
* jobs to write the new fields described above to new nodes
|
|
||||||
*
|
|
||||||
* Update the AutoIngestManager code that publishes auto ingest status
|
|
||||||
* events for the current job to update the the processing status fields
|
|
||||||
* described above in addition to publishing AutoIngestJobStatusEvents.
|
|
||||||
* Probably also need to write this data initially when a jo becomes the
|
|
||||||
* current job.
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Constructs a coordination service node data data transfer object for an
|
* Uses an auto ingest job to construct an object that converts auto ingest
|
||||||
* auto ingest manifest from the raw bytes obtained from the coordination
|
* job data for an auto ingest job coordination service node to and from
|
||||||
* service.
|
* byte arrays.
|
||||||
|
*
|
||||||
|
* @param job The job.
|
||||||
|
*/
|
||||||
|
AutoIngestJobNodeData(AutoIngestJob job) {
|
||||||
|
setProcessingStatus(job.getProcessingStatus());
|
||||||
|
setPriority(job.getPriority());
|
||||||
|
setNumberOfCrashes(numberOfCrashes); // RJCTODO
|
||||||
|
setCompletedDate(job.getCompletedDate());
|
||||||
|
setErrorsOccurred(job.getErrorsOccurred());
|
||||||
|
this.version = CURRENT_VERSION;
|
||||||
|
Manifest manifest = job.getManifest();
|
||||||
|
setManifestFilePath(manifest.getFilePath());
|
||||||
|
setManifestFileDate(manifest.getDateFileCreated());
|
||||||
|
setCaseName(manifest.getCaseName());
|
||||||
|
setDeviceId(manifest.getDeviceId());
|
||||||
|
setDataSourcePath(manifest.getDataSourcePath());
|
||||||
|
setCaseDirectoryPath(job.getCaseDirectoryPath());
|
||||||
|
setProcessingHostName(job.getProcessingHostName());
|
||||||
|
setProcessingStage(job.getProcessingStage());
|
||||||
|
setProcessingStageStartDate(job.getProcessingStageStartDate());
|
||||||
|
setProcessingStageDetails(job.getStageDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses a coordination service node data to construct an object that
|
||||||
|
* converts auto ingest job data for an auto ingest job coordination service
|
||||||
|
* node to and from byte arrays.
|
||||||
*
|
*
|
||||||
* @param nodeData The raw bytes received from the coordination service.
|
* @param nodeData The raw bytes received from the coordination service.
|
||||||
*/
|
*/
|
||||||
AutoIngestJobNodeData(byte[] nodeData) throws AutoIngestJobNodeDataException {
|
AutoIngestJobNodeData(byte[] nodeData) throws InvalidDataException {
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(nodeData);
|
if (null == nodeData || nodeData.length == 0) {
|
||||||
this.coordSvcNodeDataWasSet = buffer.hasRemaining();
|
throw new InvalidDataException(null == nodeData ? "Null nodeData byte array" : "Zero-length nodeData byte array");
|
||||||
if (this.coordSvcNodeDataWasSet) {
|
|
||||||
int rawStatus = buffer.getInt();
|
|
||||||
if (ProcessingStatus.PENDING.ordinal() == rawStatus) {
|
|
||||||
this.status = ProcessingStatus.PENDING;
|
|
||||||
} else if (ProcessingStatus.PROCESSING.ordinal() == rawStatus) {
|
|
||||||
this.status = ProcessingStatus.PROCESSING;
|
|
||||||
} else if (ProcessingStatus.COMPLETED.ordinal() == rawStatus) {
|
|
||||||
this.status = ProcessingStatus.COMPLETED;
|
|
||||||
} else if (ProcessingStatus.DELETED.ordinal() == rawStatus) {
|
|
||||||
this.status = ProcessingStatus.DELETED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set default values for all fields.
|
||||||
|
*/
|
||||||
|
this.processingStatus = AutoIngestJob.ProcessingStatus.PENDING.ordinal();
|
||||||
|
this.priority = DEFAULT_PRIORITY;
|
||||||
|
this.numberOfCrashes = 0;
|
||||||
|
this.completedDate = 0L;
|
||||||
|
this.errorsOccurred = false;
|
||||||
|
this.version = CURRENT_VERSION;
|
||||||
|
this.manifestFilePath = "";
|
||||||
|
this.manifestFileDate = 0L;
|
||||||
|
this.caseName = "";
|
||||||
|
this.deviceId = "";
|
||||||
|
this.dataSourcePath = "";
|
||||||
|
this.caseDirectoryPath = "";
|
||||||
|
this.processingHostName = "";
|
||||||
|
this.processingStage = (byte) AutoIngestJob.Stage.PENDING.ordinal();
|
||||||
|
this.processingStageStartDate = 0L;
|
||||||
|
this.processingStageDetailsDescription = "";
|
||||||
|
this.processingStageDetailsStartDate = 0L;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get fields from node data.
|
||||||
|
*/
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(nodeData);
|
||||||
|
try {
|
||||||
|
if (buffer.hasRemaining()) {
|
||||||
|
/*
|
||||||
|
* Get version 0 fields.
|
||||||
|
*/
|
||||||
|
this.processingStatus = buffer.getInt();
|
||||||
this.priority = buffer.getInt();
|
this.priority = buffer.getInt();
|
||||||
this.numberOfCrashes = buffer.getInt();
|
this.numberOfCrashes = buffer.getInt();
|
||||||
this.completedDate = buffer.getLong();
|
this.completedDate = buffer.getLong();
|
||||||
int errorFlag = buffer.getInt();
|
int errorFlag = buffer.getInt();
|
||||||
this.errorsOccurred = (1 == errorFlag);
|
this.errorsOccurred = (1 == errorFlag);
|
||||||
} else {
|
|
||||||
this.status = ProcessingStatus.PENDING;
|
|
||||||
this.priority = DEFAULT_PRIORITY;
|
|
||||||
this.numberOfCrashes = 0;
|
|
||||||
this.completedDate = 0L;
|
|
||||||
this.errorsOccurred = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
/*
|
/*
|
||||||
* There are more than 24 bytes in the buffer, so we assume the
|
* Get version 1 fields.
|
||||||
* version is greater than '0'.
|
|
||||||
*/
|
*/
|
||||||
this.version = buffer.getInt();
|
this.version = buffer.getInt();
|
||||||
if (this.version > NODE_DATA_VERSION) {
|
|
||||||
throw new AutoIngestJobNodeDataException(String.format("Node data version %d is not suppored.", this.version));
|
|
||||||
}
|
|
||||||
this.deviceId = getStringFromBuffer(buffer, TypeKind.BYTE);
|
this.deviceId = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
this.caseName = getStringFromBuffer(buffer, TypeKind.BYTE);
|
this.caseName = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
//DLG: this.caseDirectoryPath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
this.caseDirectoryPath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
this.manifestFileDate = buffer.getLong();
|
this.manifestFileDate = buffer.getLong();
|
||||||
this.manifestFilePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
this.manifestFilePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
this.dataSourcePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
this.dataSourcePath = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
//DLG: this.processingStage = getStringFromBuffer(buffer, TypeKind.BYTE);
|
this.processingStage = buffer.get();
|
||||||
//DLG: this.processingStageStartDate = buffer.getLong();
|
this.processingStageStartDate = buffer.getLong();
|
||||||
//DLG: this.processingHost = getStringFromBuffer(buffer, TypeKind.SHORT);
|
this.processingStageDetailsDescription = getStringFromBuffer(buffer, TypeKind.BYTE);
|
||||||
} else {
|
this.processingStageDetailsStartDate = buffer.getLong();;
|
||||||
this.version = 0;
|
this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT);
|
||||||
this.deviceId = "";
|
}
|
||||||
this.caseName = "";
|
|
||||||
this.caseDirectoryPath = "";
|
} catch (BufferUnderflowException ex) {
|
||||||
this.manifestFileDate = 0L;
|
throw new InvalidDataException("Node data is incomplete", ex);
|
||||||
this.manifestFilePath = "";
|
|
||||||
this.dataSourcePath = "";
|
|
||||||
this.processingStage = "";
|
|
||||||
this.processingStageStartDate = 0L;
|
|
||||||
this.processingHost = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a coordination service node data data transfer object for an
|
* Gets the processing status of the job.
|
||||||
* auto ingest manifest from values provided by the auto ingest system.
|
|
||||||
*
|
*
|
||||||
* @param manifest The manifest
|
* @return The processing status.
|
||||||
* @param status The processing status of the manifest.
|
|
||||||
* @param priority The priority of the manifest.
|
|
||||||
* @param numberOfCrashes The number of times auto ingest jobs for the
|
|
||||||
* manifest have crashed during processing.
|
|
||||||
* @param completedDate The date the auto ingest job for the manifest was
|
|
||||||
* completed.
|
|
||||||
* @param errorsOccurred Boolean to determine if errors have occurred.
|
|
||||||
*/
|
*/
|
||||||
AutoIngestJobNodeData(Manifest manifest, ProcessingStatus status, int priority, int numberOfCrashes, Date completedDate, boolean errorOccurred) {
|
AutoIngestJob.ProcessingStatus getProcessingStatus() {
|
||||||
this.coordSvcNodeDataWasSet = false;
|
return AutoIngestJob.ProcessingStatus.values()[this.processingStatus];
|
||||||
this.status = status;
|
|
||||||
this.priority = priority;
|
|
||||||
this.numberOfCrashes = numberOfCrashes;
|
|
||||||
this.completedDate = completedDate.getTime();
|
|
||||||
this.errorsOccurred = errorOccurred;
|
|
||||||
|
|
||||||
this.version = NODE_DATA_VERSION;
|
|
||||||
this.deviceId = manifest.getDeviceId();
|
|
||||||
this.caseName = manifest.getCaseName();
|
|
||||||
this.manifestFileDate = manifest.getDateFileCreated().getTime();
|
|
||||||
this.manifestFilePath = manifest.getFilePath().toString();
|
|
||||||
this.dataSourcePath = manifest.getDataSourcePath().toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the coordination service node data was set,
|
* Sets the processing status of the job.
|
||||||
* i.e., this object was constructed from raw bytes from the ccordination
|
|
||||||
* service node for the manifest.
|
|
||||||
*
|
*
|
||||||
* @return True or false.
|
* @param processingSatus The processing status.
|
||||||
*/
|
*/
|
||||||
boolean coordSvcNodeDataWasSet() {
|
void setProcessingStatus(AutoIngestJob.ProcessingStatus processingStatus) {
|
||||||
return this.coordSvcNodeDataWasSet;
|
this.processingStatus = processingStatus.ordinal();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the processing status of the manifest
|
* Gets the priority of the job.
|
||||||
*
|
*
|
||||||
* @return The processing status of the manifest.
|
* @return The priority.
|
||||||
*/
|
|
||||||
ProcessingStatus getStatus() {
|
|
||||||
return this.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the processing status of the manifest
|
|
||||||
*
|
|
||||||
* @param status The processing status of the manifest.
|
|
||||||
*/
|
|
||||||
void setStatus(ProcessingStatus status) {
|
|
||||||
this.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the priority of the manifest.
|
|
||||||
*
|
|
||||||
* @return The priority of the manifest.
|
|
||||||
*/
|
*/
|
||||||
int getPriority() {
|
int getPriority() {
|
||||||
return this.priority;
|
return this.priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the priority of the manifest. A higher number indicates a higheer
|
* Sets the priority of the job. A higher number indicates a higheer
|
||||||
* priority.
|
* priority.
|
||||||
*
|
*
|
||||||
* @param priority The priority of the manifest.
|
* @param priority The priority.
|
||||||
*/
|
*/
|
||||||
void setPriority(int priority) {
|
void setPriority(int priority) {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of times auto ingest jobs for the manifest have crashed
|
* Gets the number of times the job has crashed during processing.
|
||||||
* during processing.
|
|
||||||
*
|
*
|
||||||
* @return The number of times auto ingest jobs for the manifest have
|
* @return The number of crashes.
|
||||||
* crashed during processing.
|
|
||||||
*/
|
*/
|
||||||
int getNumberOfCrashes() {
|
int getNumberOfCrashes() {
|
||||||
return this.numberOfCrashes;
|
return this.numberOfCrashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the number of times auto ingest jobs for the manifest have crashed
|
* Sets the number of times the job has crashed during processing.
|
||||||
* during processing.
|
|
||||||
*
|
*
|
||||||
* @param numberOfCrashes The number of times auto ingest jobs for the
|
* @param numberOfCrashes The number of crashes.
|
||||||
* manifest have crashed during processing.
|
|
||||||
*/
|
*/
|
||||||
void setNumberOfCrashes(int numberOfCrashes) {
|
void setNumberOfCrashes(int numberOfCrashes) {
|
||||||
this.numberOfCrashes = numberOfCrashes;
|
this.numberOfCrashes = numberOfCrashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the date the auto ingest job for the manifest was completed.
|
* Gets the date the job was completed. A completion date equal to the epoch
|
||||||
|
* (January 1, 1970, 00:00:00 GMT), i.e., Date.getTime() returns 0L,
|
||||||
|
* indicates the job has not been completed.
|
||||||
*
|
*
|
||||||
* @return The date the auto ingest job for the manifest was completed. The
|
* @return The job completion date.
|
||||||
* epoch (January 1, 1970, 00:00:00 GMT) indicates the date is not
|
|
||||||
* set, i.e., Date.getTime() returns 0L.
|
|
||||||
*/
|
*/
|
||||||
Date getCompletedDate() {
|
Date getCompletedDate() {
|
||||||
return new Date(this.completedDate);
|
return new Date(this.completedDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the date the auto ingest job for the manifest was completed.
|
* Sets the date the job was completed. A completion date equal to the epoch
|
||||||
|
* (January 1, 1970, 00:00:00 GMT), i.e., Date.getTime() returns 0L,
|
||||||
|
* indicates the job has not been completed.
|
||||||
*
|
*
|
||||||
* @param completedDate The date the auto ingest job for the manifest was
|
* @param completedDate The job completion date.
|
||||||
* completed. Use the epoch (January 1, 1970, 00:00:00
|
|
||||||
* GMT) to indicate the date is not set, i.e., new
|
|
||||||
* Date(0L).
|
|
||||||
*/
|
*/
|
||||||
void setCompletedDate(Date completedDate) {
|
void setCompletedDate(Date completedDate) {
|
||||||
this.completedDate = completedDate.getTime();
|
this.completedDate = completedDate.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries whether or not any errors occurred during the processing of the
|
* Gets whether or not any errors occurred during the processing of the job.
|
||||||
* auto ingest job for the manifest.
|
|
||||||
*
|
*
|
||||||
* @return True or false.
|
* @return True or false.
|
||||||
*/
|
*/
|
||||||
@ -279,8 +247,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether or not any errors occurred during the processing of the auto
|
* Sets whether or not any errors occurred during the processing of job.
|
||||||
* ingest job for the manifest.
|
|
||||||
*
|
*
|
||||||
* @param errorsOccurred True or false.
|
* @param errorsOccurred True or false.
|
||||||
*/
|
*/
|
||||||
@ -289,25 +256,17 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the node data version.
|
* Gets the node data version number.
|
||||||
*
|
*
|
||||||
* @return The node data version.
|
* @return The version number.
|
||||||
*/
|
*/
|
||||||
int getVersion() {
|
int getVersion() {
|
||||||
return this.version;
|
return this.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the node data version.
|
* Gets the device ID of the device associated with the data source for the
|
||||||
*
|
* job.
|
||||||
* @param version The node data version.
|
|
||||||
*/
|
|
||||||
void setVersion(int version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the device ID.
|
|
||||||
*
|
*
|
||||||
* @return The device ID.
|
* @return The device ID.
|
||||||
*/
|
*/
|
||||||
@ -316,7 +275,8 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the device ID.
|
* Sets the device ID of the device associated with the data source for the
|
||||||
|
* job.
|
||||||
*
|
*
|
||||||
* @param deviceId The device ID.
|
* @param deviceId The device ID.
|
||||||
*/
|
*/
|
||||||
@ -325,7 +285,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the case name.
|
* Gets the case name.
|
||||||
*
|
*
|
||||||
* @return The case name.
|
* @return The case name.
|
||||||
*/
|
*/
|
||||||
@ -334,7 +294,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the case name.
|
* Sets the case name.
|
||||||
*
|
*
|
||||||
* @param caseName The case name.
|
* @param caseName The case name.
|
||||||
*/
|
*/
|
||||||
@ -342,12 +302,37 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
this.caseName = caseName;
|
this.caseName = caseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the path to the case directory of the case associated with the job.
|
||||||
|
*
|
||||||
|
* @param caseDirectoryPath The path to the case directory.
|
||||||
|
*/
|
||||||
|
synchronized void setCaseDirectoryPath(Path caseDirectoryPath) {
|
||||||
|
if (caseDirectoryPath == null) {
|
||||||
|
this.caseDirectoryPath = "";
|
||||||
|
} else {
|
||||||
|
this.caseDirectoryPath = caseDirectoryPath.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path to the case directory of the case associated with the job.
|
||||||
|
*
|
||||||
|
* @return The case directory path or null if the case directory has not
|
||||||
|
* been created yet.
|
||||||
|
*/
|
||||||
|
synchronized Path getCaseDirectoryPath() {
|
||||||
|
if (!caseDirectoryPath.isEmpty()) {
|
||||||
|
return Paths.get(caseDirectoryPath);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the date the manifest was created.
|
* Gets the date the manifest was created.
|
||||||
*
|
*
|
||||||
* @return The date the manifest was created. The epoch (January 1, 1970,
|
* @return The date the manifest was created.
|
||||||
* 00:00:00 GMT) indicates the date is not set, i.e., Date.getTime()
|
|
||||||
* returns 0L.
|
|
||||||
*/
|
*/
|
||||||
Date getManifestFileDate() {
|
Date getManifestFileDate() {
|
||||||
return new Date(this.manifestFileDate);
|
return new Date(this.manifestFileDate);
|
||||||
@ -356,16 +341,14 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* Sets the date the manifest was created.
|
* Sets the date the manifest was created.
|
||||||
*
|
*
|
||||||
* @param manifestFileDate The date the manifest was created. Use the epoch
|
* @param manifestFileDate The date the manifest was created.
|
||||||
* (January 1, 1970, 00:00:00 GMT) to indicate the
|
|
||||||
* date is not set, i.e., new Date(0L).
|
|
||||||
*/
|
*/
|
||||||
void setManifestFileDate(Date manifestFileDate) {
|
void setManifestFileDate(Date manifestFileDate) {
|
||||||
this.manifestFileDate = manifestFileDate.getTime();
|
this.manifestFileDate = manifestFileDate.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the manifest file path.
|
* Gets the manifest file path.
|
||||||
*
|
*
|
||||||
* @return The manifest file path.
|
* @return The manifest file path.
|
||||||
*/
|
*/
|
||||||
@ -374,7 +357,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the manifest file path.
|
* Sets the manifest file path.
|
||||||
*
|
*
|
||||||
* @param manifestFilePath The manifest file path.
|
* @param manifestFilePath The manifest file path.
|
||||||
*/
|
*/
|
||||||
@ -387,7 +370,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data source path.
|
* Gets the path of the data source for the job.
|
||||||
*
|
*
|
||||||
* @return The data source path.
|
* @return The data source path.
|
||||||
*/
|
*/
|
||||||
@ -396,7 +379,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file name portion of the data source path.
|
* Get the file name portion of the path of the data source for the job.
|
||||||
*
|
*
|
||||||
* @return The data source file name.
|
* @return The data source file name.
|
||||||
*/
|
*/
|
||||||
@ -405,7 +388,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the data source path.
|
* Sets the path of the data source for the job.
|
||||||
*
|
*
|
||||||
* @param dataSourcePath The data source path.
|
* @param dataSourcePath The data source path.
|
||||||
*/
|
*/
|
||||||
@ -418,16 +401,91 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the node data as raw bytes that can be sent to the coordination
|
* Get the processing stage of the job.
|
||||||
|
*
|
||||||
|
* @return The processing stage.
|
||||||
|
*/
|
||||||
|
AutoIngestJob.Stage getProcessingStage() {
|
||||||
|
return AutoIngestJob.Stage.values()[this.processingStage];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing stage job.
|
||||||
|
*
|
||||||
|
* @param processingStage The processing stage.
|
||||||
|
*/
|
||||||
|
void setProcessingStage(AutoIngestJob.Stage processingStage) {
|
||||||
|
this.processingStage = (byte) processingStage.ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processing stage start date.
|
||||||
|
*
|
||||||
|
* @return The processing stage start date.
|
||||||
|
*/
|
||||||
|
Date getProcessingStageStartDate() {
|
||||||
|
return new Date(this.processingStageStartDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing stage start date.
|
||||||
|
*
|
||||||
|
* @param processingStageStartDate The processing stage start date.
|
||||||
|
*/
|
||||||
|
void setProcessingStageStartDate(Date processingStageStartDate) {
|
||||||
|
this.processingStageStartDate = processingStageStartDate.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the processing stage details.
|
||||||
|
*
|
||||||
|
* @return A processing stage details object.
|
||||||
|
*/
|
||||||
|
AutoIngestJob.StageDetails getProcessingStageDetails() {
|
||||||
|
return new AutoIngestJob.StageDetails(this.processingStageDetailsDescription, new Date(this.processingStageDetailsStartDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the details of the current processing stage.
|
||||||
|
*
|
||||||
|
* @param stageDetails A stage details object.
|
||||||
|
*/
|
||||||
|
void setProcessingStageDetails(AutoIngestJob.StageDetails stageDetails) {
|
||||||
|
this.processingStageDetailsDescription = stageDetails.getDescription();
|
||||||
|
this.processingStageDetailsStartDate = stageDetails.getStartDate().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the processing host name, may be the empty string.
|
||||||
|
*
|
||||||
|
* @return The processing host. The empty string if the job is not currently
|
||||||
|
* being processed.
|
||||||
|
*/
|
||||||
|
String getProcessingHostName() {
|
||||||
|
return this.processingHostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the processing host name. May be the empty string.
|
||||||
|
*
|
||||||
|
* @param processingHost The processing host name. The empty string if the
|
||||||
|
* job is not currently being processed.
|
||||||
|
*/
|
||||||
|
void setProcessingHostName(String processingHost) {
|
||||||
|
this.processingHostName = processingHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the node data as a byte array that can be sent to the coordination
|
||||||
* service.
|
* service.
|
||||||
*
|
*
|
||||||
* @return The manifest node data as a byte array.
|
* @return The node data as a byte array.
|
||||||
*/
|
*/
|
||||||
byte[] toArray() {
|
byte[] toArray() {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(MAX_POSSIBLE_NODE_DATA_SIZE);
|
ByteBuffer buffer = ByteBuffer.allocate(MAX_POSSIBLE_NODE_DATA_SIZE);
|
||||||
|
|
||||||
// Write data (compatible with version 0)
|
// Write data (compatible with version 0)
|
||||||
buffer.putInt(this.status.ordinal());
|
buffer.putInt(this.processingStatus);
|
||||||
buffer.putInt(this.priority);
|
buffer.putInt(this.priority);
|
||||||
buffer.putInt(this.numberOfCrashes);
|
buffer.putInt(this.numberOfCrashes);
|
||||||
buffer.putLong(this.completedDate);
|
buffer.putLong(this.completedDate);
|
||||||
@ -440,13 +498,15 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
// Write data
|
// Write data
|
||||||
putStringIntoBuffer(deviceId, buffer, TypeKind.BYTE);
|
putStringIntoBuffer(deviceId, buffer, TypeKind.BYTE);
|
||||||
putStringIntoBuffer(caseName, buffer, TypeKind.BYTE);
|
putStringIntoBuffer(caseName, buffer, TypeKind.BYTE);
|
||||||
//DLG: putStringIntoBuffer(caseDirectoryPath, buffer, TypeKind.SHORT);
|
putStringIntoBuffer(caseDirectoryPath, buffer, TypeKind.SHORT);
|
||||||
buffer.putLong(this.manifestFileDate);
|
buffer.putLong(this.manifestFileDate);
|
||||||
putStringIntoBuffer(manifestFilePath, buffer, TypeKind.SHORT);
|
putStringIntoBuffer(manifestFilePath, buffer, TypeKind.SHORT);
|
||||||
putStringIntoBuffer(dataSourcePath, buffer, TypeKind.SHORT);
|
putStringIntoBuffer(dataSourcePath, buffer, TypeKind.SHORT);
|
||||||
//DLG: putStringIntoBuffer(processingStage, buffer, TypeKind.BYTE);
|
buffer.put(this.processingStage);
|
||||||
//DLG: buffer.putLong(this.processingStageStartDate);
|
buffer.putLong(this.processingStageStartDate);
|
||||||
//DLG: putStringIntoBuffer(processingHost, buffer, TypeKind.SHORT);
|
putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE);
|
||||||
|
buffer.putLong(this.processingStageDetailsStartDate);
|
||||||
|
putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the array
|
// Prepare the array
|
||||||
@ -457,6 +517,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DGL: Document what is going on here and how the max buffer sie constant is calculated.
|
||||||
private String getStringFromBuffer(ByteBuffer buffer, TypeKind lengthType) {
|
private String getStringFromBuffer(ByteBuffer buffer, TypeKind lengthType) {
|
||||||
int length = 0;
|
int length = 0;
|
||||||
String output = "";
|
String output = "";
|
||||||
@ -479,6 +540,7 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DGL: Document what is going on here and how the max buffer sie constant is calculated.
|
||||||
private void putStringIntoBuffer(String stringValue, ByteBuffer buffer, TypeKind lengthType) {
|
private void putStringIntoBuffer(String stringValue, ByteBuffer buffer, TypeKind lengthType) {
|
||||||
switch (lengthType) {
|
switch (lengthType) {
|
||||||
case BYTE:
|
case BYTE:
|
||||||
@ -492,14 +554,17 @@ final class AutoIngestJobNodeData implements Serializable {
|
|||||||
buffer.put(stringValue.getBytes());
|
buffer.put(stringValue.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
final static class InvalidDataException extends Exception {
|
||||||
* Processing status for the auto ingest job for the manifest.
|
|
||||||
*/
|
private static final long serialVersionUID = 1L;
|
||||||
enum ProcessingStatus {
|
|
||||||
PENDING,
|
private InvalidDataException(String message) {
|
||||||
PROCESSING,
|
super(message);
|
||||||
COMPLETED,
|
}
|
||||||
DELETED
|
|
||||||
|
private InvalidDataException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2017 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.experimental.autoingest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when a manifest node contains incompatible data.
|
|
||||||
*/
|
|
||||||
public class AutoIngestJobNodeDataException extends Exception {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an exception thrown when a manifest node contains incompatible
|
|
||||||
* data.
|
|
||||||
*
|
|
||||||
* @param message An error message.
|
|
||||||
*/
|
|
||||||
public AutoIngestJobNodeDataException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an exception thrown when a manifest node contains incompatible
|
|
||||||
* data.
|
|
||||||
*
|
|
||||||
* @param message An error message.
|
|
||||||
* @param cause An exception that caused this exception to be thrown.
|
|
||||||
*/
|
|
||||||
public AutoIngestJobNodeDataException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import java.awt.Cursor;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -33,12 +34,14 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.annotation.concurrent.GuardedBy;
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEventException;
|
import org.sleuthkit.autopsy.events.AutopsyEventException;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
||||||
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An auto ingest monitor responsible for monitoring and reporting the
|
* An auto ingest monitor responsible for monitoring and reporting the
|
||||||
@ -140,8 +143,10 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private void handleJobStartedEvent(AutoIngestJobStartedEvent event) {
|
private void handleJobStartedEvent(AutoIngestJobStartedEvent event) {
|
||||||
synchronized (jobsLock) {
|
synchronized (jobsLock) {
|
||||||
// DLG: Remove job from pending queue, if present
|
// DLG: TEST! Remove job from pending queue, if present
|
||||||
// DLG: Add job to running jobs list
|
// DLG: TEST! Add job to running jobs list
|
||||||
|
jobsSnapshot.removePendingJob(event.getJob());
|
||||||
|
jobsSnapshot.addOrReplaceRunningJob(event.getJob());
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(jobsSnapshot);
|
notifyObservers(jobsSnapshot);
|
||||||
}
|
}
|
||||||
@ -154,7 +159,8 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private void handleJobStatusEvent(AutoIngestJobStatusEvent event) {
|
private void handleJobStatusEvent(AutoIngestJobStatusEvent event) {
|
||||||
synchronized (jobsLock) {
|
synchronized (jobsLock) {
|
||||||
// DLG: Replace job in running list with job from event
|
// DLG: TEST! Replace job in running list with job from event
|
||||||
|
jobsSnapshot.addOrReplaceRunningJob(event.getJob());
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(jobsSnapshot);
|
notifyObservers(jobsSnapshot);
|
||||||
}
|
}
|
||||||
@ -167,8 +173,10 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private void handleJobCompletedEvent(AutoIngestJobCompletedEvent event) {
|
private void handleJobCompletedEvent(AutoIngestJobCompletedEvent event) {
|
||||||
synchronized (jobsLock) {
|
synchronized (jobsLock) {
|
||||||
// DLG: Remove job from event from running list, if present
|
// DLG: TEST! Remove job from event from running list, if present
|
||||||
// DLG: Add job to completed list
|
// DLG: TEST! Add job to completed list
|
||||||
|
jobsSnapshot.removeRunningJob(event.getJob());
|
||||||
|
jobsSnapshot.addOrReplaceCompletedJob(event.getJob());
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(jobsSnapshot);
|
notifyObservers(jobsSnapshot);
|
||||||
}
|
}
|
||||||
@ -180,12 +188,7 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
* @param event A job/case prioritization event.
|
* @param event A job/case prioritization event.
|
||||||
*/
|
*/
|
||||||
private void handleCasePrioritizationEvent(AutoIngestCasePrioritizedEvent event) {
|
private void handleCasePrioritizationEvent(AutoIngestCasePrioritizedEvent event) {
|
||||||
synchronized (jobsLock) {
|
coordSvcQueryExecutor.submit(new CoordinationServiceQueryTask());
|
||||||
// DLG: Replace job in pending queue with job from event
|
|
||||||
// DLG: See 'bnPrioritizeCaseActionPerformed(ActionEvent)' in the AutoIngestControlPanel class!!!
|
|
||||||
setChanged();
|
|
||||||
notifyObservers(jobsSnapshot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,9 +239,31 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
JobsSnapshot newJobsSnapshot = new JobsSnapshot();
|
JobsSnapshot newJobsSnapshot = new JobsSnapshot();
|
||||||
List<String> nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS);
|
List<String> nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.MANIFESTS);
|
||||||
for (String node : nodeList) {
|
for (String node : nodeList) {
|
||||||
// DLG: Do not need a lock here
|
try {
|
||||||
// DLG: Get the node data and construct a AutoIngestJobNodeData object (rename AutoIngestJobNodeData => AutoIngestJobData)
|
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node));
|
||||||
// DLG: Construct an AutoIngestJob object from the AutoIngestJobNodeData object, need new AutoIngestJob constructor
|
AutoIngestJob job = new AutoIngestJob(nodeData);
|
||||||
|
ProcessingStatus processingStatus = nodeData.getProcessingStatus();
|
||||||
|
switch (processingStatus) {
|
||||||
|
case PENDING:
|
||||||
|
newJobsSnapshot.addOrReplacePendingJob(job);
|
||||||
|
break;
|
||||||
|
case PROCESSING:
|
||||||
|
newJobsSnapshot.addOrReplaceRunningJob(job);
|
||||||
|
break;
|
||||||
|
case COMPLETED:
|
||||||
|
newJobsSnapshot.addOrReplaceCompletedJob(job);
|
||||||
|
break;
|
||||||
|
case DELETED:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex);
|
||||||
|
} catch (AutoIngestJobNodeData.InvalidDataException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return newJobsSnapshot;
|
return newJobsSnapshot;
|
||||||
} catch (CoordinationServiceException ex) {
|
} catch (CoordinationServiceException ex) {
|
||||||
@ -261,10 +286,10 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
* the pending jobs queue.
|
* the pending jobs queue.
|
||||||
*/
|
*/
|
||||||
for (AutoIngestJob job : jobsSnapshot.getPendingJobs()) {
|
for (AutoIngestJob job : jobsSnapshot.getPendingJobs()) {
|
||||||
if (job.getNodeData().getPriority() > highestPriority) {
|
if (job.getPriority() > highestPriority) {
|
||||||
highestPriority = job.getNodeData().getPriority();
|
highestPriority = job.getPriority();
|
||||||
}
|
}
|
||||||
if (job.getNodeData().getManifestFilePath().equals(manifestFilePath)) {
|
if (job.getManifest().getFilePath().equals(manifestFilePath)) {
|
||||||
prioritizedJob = job;
|
prioritizedJob = job;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,22 +300,22 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
if (null != prioritizedJob) {
|
if (null != prioritizedJob) {
|
||||||
++highestPriority;
|
++highestPriority;
|
||||||
String manifestNodePath = prioritizedJob.getNodeData().getManifestFilePath().toString();
|
String manifestNodePath = prioritizedJob.getManifest().getFilePath().toString();
|
||||||
try {
|
try {
|
||||||
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath));
|
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath));
|
||||||
nodeData.setPriority(highestPriority);
|
nodeData.setPriority(highestPriority);
|
||||||
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray());
|
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray());
|
||||||
} catch (AutoIngestJobNodeDataException | CoordinationServiceException | InterruptedException ex) {
|
} catch (AutoIngestJobNodeData.InvalidDataException | CoordinationServiceException | InterruptedException ex) {
|
||||||
throw new AutoIngestMonitorException("Error bumping priority for job " + prioritizedJob.toString(), ex);
|
throw new AutoIngestMonitorException("Error bumping priority for job " + prioritizedJob.toString(), ex);
|
||||||
}
|
}
|
||||||
prioritizedJob.getNodeData().setPriority(highestPriority);
|
prioritizedJob.setPriority(highestPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Publish a prioritization event.
|
* Publish a prioritization event.
|
||||||
*/
|
*/
|
||||||
if (null != prioritizedJob) {
|
if (null != prioritizedJob) {
|
||||||
final String caseName = prioritizedJob.getNodeData().getCaseName();
|
final String caseName = prioritizedJob.getManifest().getCaseName();
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName));
|
eventPublisher.publishRemotely(new AutoIngestCasePrioritizedEvent(LOCAL_HOST_NAME, caseName));
|
||||||
}).start();
|
}).start();
|
||||||
|
@ -18,11 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Arrays;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
@ -42,24 +42,11 @@ import org.xml.sax.SAXException;
|
|||||||
public final class AutopsyManifestFileParser implements ManifestFileParser {
|
public final class AutopsyManifestFileParser implements ManifestFileParser {
|
||||||
|
|
||||||
private static final String MANIFEST_FILE_NAME_SIGNATURE = "_MANIFEST.XML";
|
private static final String MANIFEST_FILE_NAME_SIGNATURE = "_MANIFEST.XML";
|
||||||
private static final String NMEC_MANIFEST_ELEM_TAG_NAME = "NMEC_Manifest";
|
private static final String ROOT_ELEM_TAG_NAME = "AutopsyManifest";
|
||||||
private static final String MANIFEST_ELEM_TAG_NAME = "Manifest";
|
private static final String CASE_NAME_XPATH = "/AutopsyManifest/CaseName/text()";
|
||||||
private static final String CASE_NAME_XPATH = "/Collection/Name/text()";
|
private static final String DEVICE_ID_XPATH = "/AutopsyManifest/DeviceId/text()";
|
||||||
private static final String DEVICE_ID_XPATH = "/Collection/Image/ID/text()";
|
private static final String DATA_SOURCE_NAME_XPATH = "/AutopsyManifest/DataSource/text()";
|
||||||
private static final String IMAGE_NAME_XPATH = "/Collection/Image/Name/text()";
|
|
||||||
private static final String IMAGE_FULL_NAME_XPATH = "/Collection/Image/FullName/text()";
|
|
||||||
private static final String IMAGE_RELATIVE_PATH_XPATH = "/Collection/Image/RelativePath/text()";
|
|
||||||
|
|
||||||
private String actualRootElementTag = "";
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the given file is a supported manifest file.
|
|
||||||
*
|
|
||||||
* @param filePath
|
|
||||||
*
|
|
||||||
* @return true if this is a supported manifest file, otherwise false
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fileIsManifest(Path filePath) {
|
public boolean fileIsManifest(Path filePath) {
|
||||||
boolean fileIsManifest = false;
|
boolean fileIsManifest = false;
|
||||||
@ -68,9 +55,7 @@ public final class AutopsyManifestFileParser implements ManifestFileParser {
|
|||||||
if (fileName.toString().toUpperCase().endsWith(MANIFEST_FILE_NAME_SIGNATURE)) {
|
if (fileName.toString().toUpperCase().endsWith(MANIFEST_FILE_NAME_SIGNATURE)) {
|
||||||
Document doc = this.createManifestDOM(filePath);
|
Document doc = this.createManifestDOM(filePath);
|
||||||
Element docElement = doc.getDocumentElement();
|
Element docElement = doc.getDocumentElement();
|
||||||
actualRootElementTag = docElement.getTagName();
|
fileIsManifest = docElement.getTagName().equals(ROOT_ELEM_TAG_NAME);
|
||||||
fileIsManifest = actualRootElementTag.equals(MANIFEST_ELEM_TAG_NAME) ||
|
|
||||||
actualRootElementTag.equals(NMEC_MANIFEST_ELEM_TAG_NAME);
|
|
||||||
}
|
}
|
||||||
} catch (Exception unused) {
|
} catch (Exception unused) {
|
||||||
fileIsManifest = false;
|
fileIsManifest = false;
|
||||||
@ -78,95 +63,30 @@ public final class AutopsyManifestFileParser implements ManifestFileParser {
|
|||||||
return fileIsManifest;
|
return fileIsManifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the given manifest file and create a Manifest object.
|
|
||||||
*
|
|
||||||
* @param filePath Fully qualified path to manifest file
|
|
||||||
*
|
|
||||||
* @return A Manifest object representing the parsed manifest file.
|
|
||||||
*
|
|
||||||
* @throws ManifestFileParserException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Manifest parse(Path filePath) throws ManifestFileParserException {
|
public Manifest parse(Path filePath) throws ManifestFileParserException {
|
||||||
try {
|
try {
|
||||||
|
BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);
|
||||||
|
Date dateFileCreated = new Date(attrs.creationTime().toMillis());
|
||||||
Document doc = this.createManifestDOM(filePath);
|
Document doc = this.createManifestDOM(filePath);
|
||||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
XPathExpression expr = xpath.compile(constructXPathExpression(CASE_NAME_XPATH));
|
XPathExpression expr = xpath.compile(CASE_NAME_XPATH);
|
||||||
String caseName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
String caseName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||||
expr = xpath.compile(constructXPathExpression(DEVICE_ID_XPATH));
|
expr = xpath.compile(DEVICE_ID_XPATH);
|
||||||
String deviceId = (String) expr.evaluate(doc, XPathConstants.STRING);
|
String deviceId = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||||
Path dataSourcePath = determineDataSourcePath(filePath, doc);
|
expr = xpath.compile(DATA_SOURCE_NAME_XPATH);
|
||||||
return new Manifest(filePath, caseName, deviceId, dataSourcePath, new HashMap<>());
|
String dataSourceName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||||
|
Path dataSourcePath = filePath.getParent().resolve(dataSourceName);
|
||||||
|
return new Manifest(filePath, dateFileCreated, caseName, deviceId, dataSourcePath, new HashMap<>());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new ManifestFileParserException(String.format("Error parsing manifest %s", filePath), ex);
|
throw new ManifestFileParserException(String.format("Error parsing manifest %s", filePath), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new DOM document object for the given manifest file.
|
|
||||||
*
|
|
||||||
* @param manifestFilePath Fully qualified path to manifest file.
|
|
||||||
*
|
|
||||||
* @return DOM document object
|
|
||||||
*
|
|
||||||
* @throws ParserConfigurationException
|
|
||||||
* @throws SAXException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private Document createManifestDOM(Path manifestFilePath) throws ParserConfigurationException, SAXException, IOException {
|
private Document createManifestDOM(Path manifestFilePath) throws ParserConfigurationException, SAXException, IOException {
|
||||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||||
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||||
return docBuilder.parse(manifestFilePath.toFile());
|
return docBuilder.parse(manifestFilePath.toFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an XPath expression string relative to the actual root
|
|
||||||
* element of the manifest for the given path.
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* @return XPath expression string.
|
|
||||||
*/
|
|
||||||
private String constructXPathExpression(String path) {
|
|
||||||
return "/" + actualRootElementTag + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to find a valid (existing) data source for the manifest file.
|
|
||||||
*
|
|
||||||
* @param manifestFilePath Fully qualified path to manifest file.
|
|
||||||
* @param doc DOM document object for the manifest file.
|
|
||||||
* @return Path to an existing data source.
|
|
||||||
* @throws ManifestFileParserException if an error occurred while parsing manifest file.
|
|
||||||
*/
|
|
||||||
private Path determineDataSourcePath(Path manifestFilePath, Document doc) throws ManifestFileParserException {
|
|
||||||
String dataSourcePath = "";
|
|
||||||
try {
|
|
||||||
for (String element : Arrays.asList(IMAGE_NAME_XPATH, IMAGE_FULL_NAME_XPATH, IMAGE_RELATIVE_PATH_XPATH)) {
|
|
||||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
|
||||||
XPathExpression expr = xpath.compile(constructXPathExpression(element));
|
|
||||||
String fileName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
|
||||||
if (fileName.contains("\\")) {
|
|
||||||
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
dataSourcePath = manifestFilePath.getParent().resolve(fileName).toString();
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
// NOTE: exceptions can be thrown by resolve() method based on contents of the manifest file.
|
|
||||||
// For example if file name is "test .txt" and in one of the path fields they only enter "test "
|
|
||||||
// i.e. the file name without extension.
|
|
||||||
// We should continue on to the next XML path field
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (new File(dataSourcePath).exists()) {
|
|
||||||
// found the data source
|
|
||||||
return Paths.get(dataSourcePath);
|
|
||||||
}
|
|
||||||
// keep trying other XML fields
|
|
||||||
}
|
|
||||||
return Paths.get(dataSourcePath);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new ManifestFileParserException(String.format("Error parsing manifest %s", manifestFilePath), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ AutoIngestDashboard.DeletionFailed=Deletion failed for job
|
|||||||
AutoIngestDashboard.ShowLogFailed.Title=Unable to display case log
|
AutoIngestDashboard.ShowLogFailed.Title=Unable to display case log
|
||||||
AutoIngestDashboard.ShowLogFailed.Message=Case log file does not exist
|
AutoIngestDashboard.ShowLogFailed.Message=Case log file does not exist
|
||||||
AutoIngestDashboard.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue.
|
AutoIngestDashboard.bnPrioritizeCase.toolTipText=Move all images associated with a case to top of Pending queue.
|
||||||
AutoIngestDashboard.bnPrioritizeCase.text=Prioritize Case
|
|
||||||
AutoIngestDashboard.ExitConsequences=This will cancel any currently running job on this host. Exiting while a job is running potentially leaves the case in an inconsistent or corrupted state.
|
AutoIngestDashboard.ExitConsequences=This will cancel any currently running job on this host. Exiting while a job is running potentially leaves the case in an inconsistent or corrupted state.
|
||||||
AutoIngestDashboard.ExitingStatus=Exiting...
|
AutoIngestDashboard.ExitingStatus=Exiting...
|
||||||
AutoIngestDashboard.OK=OK
|
AutoIngestDashboard.OK=OK
|
||||||
@ -275,3 +274,4 @@ AutoIngestDashboard.prioritizeButton.toolTipText=Prioritizes the selected job
|
|||||||
AutoIngestDashboard.prioritizeButton.text=&Prioritize
|
AutoIngestDashboard.prioritizeButton.text=&Prioritize
|
||||||
AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables
|
AutoIngestDashboard.refreshButton.toolTipText=Refresh displayed tables
|
||||||
AutoIngestDashboard.refreshButton.text=&Refresh
|
AutoIngestDashboard.refreshButton.text=&Refresh
|
||||||
|
AutoIngestDashboard.jButton1.text=jButton1
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2015 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,12 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -40,10 +37,9 @@ public final class Manifest implements Serializable {
|
|||||||
private final String dataSourcePath;
|
private final String dataSourcePath;
|
||||||
private final Map<String, String> manifestProperties;
|
private final Map<String, String> manifestProperties;
|
||||||
|
|
||||||
public Manifest(Path manifestFilePath, String caseName, String deviceId, Path dataSourcePath, Map<String, String> manifestProperties) throws IOException {
|
public Manifest(Path manifestFilePath, Date dateFileCreated, String caseName, String deviceId, Path dataSourcePath, Map<String, String> manifestProperties) {
|
||||||
this.filePath = manifestFilePath.toString();
|
this.filePath = manifestFilePath.toString();
|
||||||
BasicFileAttributes attrs = Files.readAttributes(manifestFilePath, BasicFileAttributes.class);
|
this.dateFileCreated = dateFileCreated;
|
||||||
this.dateFileCreated = new Date(attrs.creationTime().toMillis());
|
|
||||||
this.caseName = caseName;
|
this.caseName = caseName;
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
if (dataSourcePath != null) {
|
if (dataSourcePath != null) {
|
||||||
|
@ -637,7 +637,7 @@ class ExtractedContentPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NbBundle.Messages({"# 0 - Content name",
|
@NbBundle.Messages({"# {0} - Content name",
|
||||||
"ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}"})
|
"ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}"})
|
||||||
protected String doInBackground() throws Exception {
|
protected String doInBackground() throws Exception {
|
||||||
progress = ProgressHandle.createHandle(Bundle.ExtractedContentPanel_SetMarkup_progress_loading(contentName));
|
progress = ProgressHandle.createHandle(Bundle.ExtractedContentPanel_SetMarkup_progress_loading(contentName));
|
||||||
|
@ -68,6 +68,9 @@ and added to the list of Interesting Items.
|
|||||||
|
|
||||||
\image html central_repo_manage_tags.png
|
\image html central_repo_manage_tags.png
|
||||||
|
|
||||||
|
If a case is open, checking the Implies Known Bad checkbox will give you the option to add the known bad status to anything in the current case
|
||||||
|
that has already been tagged. For example, if you create a tag named "Alpha", tag a few items and then go into Manage Tags and check the box for the Alpha tag, you can optionally choose to have the status for those tagged items changed in the Central Repository. The effect is the same as if you had checked the box in Manage Tags before tagging the items. Note that data from any previous cases will not be changed.
|
||||||
|
|
||||||
By default there is a tag called "Evidence" as the only tag associated with this module. To associate one or more tag(s) with this module, check the Correlate box next to the tag
|
By default there is a tag called "Evidence" as the only tag associated with this module. To associate one or more tag(s) with this module, check the Correlate box next to the tag
|
||||||
name(s) and click OK. To create additional tags, use the Tags options panel.
|
name(s) and click OK. To create additional tags, use the Tags options panel.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user