Merge branch 'sleuthkit:develop' into develop

This commit is contained in:
Seb2lyon 2021-06-17 17:58:04 +02:00 committed by GitHub
commit 05e50ce769
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 538 additions and 398 deletions

View File

@ -26,8 +26,10 @@ import java.util.Date;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
@ -51,12 +53,13 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE);
private static final int EXTRA_ROW_HEIGHT = 4;
private List<IngestJobInfo> ingestJobs;
private final List<IngestJobInfo> ingestJobs = new ArrayList<>();
private final List<IngestJobInfo> ingestJobsForSelectedDataSource = new ArrayList<>();
private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel();
private IngestModuleTableModel ingestModuleTableModel = new IngestModuleTableModel(null);
private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private DataSource selectedDataSource;
private static SwingWorker<Boolean, Void> refreshWorker = null;
/**
* Creates new form IngestJobInfoPanel
@ -76,19 +79,19 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
this.ingestModuleTable.setModel(this.ingestModuleTableModel);
});
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST , (PropertyChangeEvent evt) -> {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
if (evt.getPropertyName().equals(IngestManager.IngestJobEvent.STARTED.toString())
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|| evt.getPropertyName().equals(IngestManager.IngestJobEvent.COMPLETED.toString())) {
refresh();
}
});
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, (PropertyChangeEvent evt) -> {
if (!(evt instanceof AutopsyEvent) || (((AutopsyEvent) evt).getSourceType() != AutopsyEvent.SourceType.LOCAL)) {
return;
}
// Check whether we have a case open or case close event.
if ((CURRENT_CASE == Case.Events.valueOf(evt.getPropertyName()))) {
if (evt.getNewValue() != null) {
@ -102,7 +105,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
});
ingestJobTable.setRowHeight(ingestJobTable.getRowHeight() + EXTRA_ROW_HEIGHT);
ingestModuleTable.setRowHeight(ingestModuleTable.getRowHeight() + EXTRA_ROW_HEIGHT);
}
/**
@ -133,27 +136,51 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
* Get the updated complete list of ingest jobs.
*/
private void refresh() {
try {
if (Case.isCaseOpen()) { // Note - this will generally return true when handling a case close event
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
this.ingestJobs = skCase.getIngestJobs();
setDataSource(selectedDataSource);
} else {
this.ingestJobs = new ArrayList<>();
setDataSource(null);
}
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex);
JOptionPane.showMessageDialog(this, Bundle.IngestJobInfoPanel_loadIngestJob_error_text(), Bundle.IngestJobInfoPanel_loadIngestJob_error_title(), JOptionPane.ERROR_MESSAGE);
if (refreshWorker != null && !refreshWorker.isDone()) {
refreshWorker.cancel(true);
}
refreshWorker = new SwingWorker<Boolean, Void>() {
@Override
protected Boolean doInBackground() throws Exception {
ingestJobs.clear();
try {
if (Case.isCaseOpen()) { // Note - this will generally return true when handling a case close event
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
ingestJobs.addAll(skCase.getIngestJobs());
setDataSource(selectedDataSource);
} else {
setDataSource(null);
}
return true;
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex);
return false;
}
}
@Override
protected void done() {
try {
if (!get()) {
JOptionPane.showMessageDialog(IngestJobInfoPanel.this, Bundle.IngestJobInfoPanel_loadIngestJob_error_text(), Bundle.IngestJobInfoPanel_loadIngestJob_error_title(), JOptionPane.ERROR_MESSAGE);
}
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.WARNING, "Error getting results from Ingest Job Info Panel's refresh worker", ex);
}
}
};
refreshWorker.execute();
}
/**
* Reset the panel.
*/
private void reset() {
this.ingestJobs = new ArrayList<>();
if (refreshWorker != null) {
refreshWorker.cancel(true);
}
this.ingestJobs.clear();
setDataSource(null);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -119,9 +119,9 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie
updateOutlineViewPanel();
}
});
TableColumn column = outline.getColumnModel().getColumn(2);
column.setCellRenderer(new NodeTableCellRenderer() );
column.setCellRenderer(new NodeTableCellRenderer());
}
@ -164,7 +164,9 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie
@Override
public void setSelectionInfo(SelectionInfo info) {
callLogDataViewer.setNode(null);
nodeFactory.refresh(info);
}
@Override
@ -229,7 +231,7 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane bottomScrollPane;
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel outlineViewPanel;

View File

@ -35,7 +35,8 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* ChildFactory for ContactNodes.
*/
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact> {
private static final Logger logger = Logger.getLogger(ContactsChildNodeFactory.class.getName());
private SelectionInfo selectionInfo;
@ -47,12 +48,13 @@ final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
* accounts
*/
ContactsChildNodeFactory(SelectionInfo selectionInfo) {
this.selectionInfo = selectionInfo;
this.selectionInfo = selectionInfo;
}
/**
* Updates the current instance of selectionInfo and calls the refresh method.
*
* Updates the current instance of selectionInfo and calls the refresh
* method.
*
* @param selectionInfo New instance of the currently selected accounts
*/
public void refresh(SelectionInfo selectionInfo) {
@ -63,13 +65,15 @@ final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
/**
* Creates a list of Keys (BlackboardArtifact) for only contacts of the
* currently selected accounts
*
* @param list List of BlackboardArtifact to populate
*
* @return True on success
*/
@Override
protected boolean createKeys(List<BlackboardArtifact> list) {
if(selectionInfo == null) {
if (selectionInfo == null) {
return true;
}
@ -80,7 +84,7 @@ final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
logger.log(Level.SEVERE, "Failed to load relationship sources.", ex); //NON-NLS
return false;
}
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
BlackboardArtifact bba = (BlackboardArtifact) content;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -35,7 +35,6 @@ import org.openide.nodes.NodeAdapter;
import org.openide.nodes.NodeMemberEvent;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
@ -126,6 +125,7 @@ final class ContactsViewer extends JPanel implements RelationshipsViewer {
@Override
public void setSelectionInfo(SelectionInfo info) {
contactPane.setNode(null);
nodeFactory.refresh(info);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -99,18 +99,19 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
public void setSelectionInfo(SelectionInfo info) {
Set<Content> relationshipSources;
Set<BlackboardArtifact> artifactList = new HashSet<>();
contentViewer.setNode(null);
if (info != null) {
try {
relationshipSources = info.getRelationshipSources();
try {
relationshipSources = info.getRelationshipSources();
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
artifactList.add((BlackboardArtifact) content);
});
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
artifactList.add((BlackboardArtifact) content);
});
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to update selection.", ex);
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Unable to update selection.", ex);
}
}
thumbnailViewer.resetComponent();
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentThumbnailsChildren(artifactList)), tableEM), true, this.getClass().getName()));

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.communications.relationships;
import java.awt.Component;
import javax.swing.JPanel;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
@ -37,15 +36,15 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
*/
public RelationshipBrowser() {
initComponents();
MessageViewer messagesViewer = new MessageViewer();
ContactsViewer contactsViewer = new ContactsViewer();
SummaryViewer summaryViewer = new SummaryViewer();
MediaViewer mediaViewer = new MediaViewer();
CallLogViewer callLogViewer = new CallLogViewer();
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
tabPane.add(callLogViewer.getDisplayName(), callLogViewer);
@ -95,13 +94,11 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider
}// </editor-fold>//GEN-END:initComponents
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
if(currentSelection != null) {
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection);
}
Component selectedComponent = tabPane.getSelectedComponent();
if(selectedComponent instanceof Lookup.Provider) {
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
RelationshipsViewer viewer = ((RelationshipsViewer) tabPane.getSelectedComponent());
//clear old values
viewer.setSelectionInfo(currentSelection);
if (viewer instanceof Lookup.Provider) {
Lookup lookup = viewer.getLookup();
proxyLookup.setNewLookups(lookup);
}
}//GEN-LAST:event_tabPaneStateChanged

View File

@ -97,30 +97,28 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
public void setArtifact(BlackboardArtifact artifact) {
resetComponent();
if (artifact == null) {
return;
}
CallLogViewData callLogViewData = null;
try {
callLogViewData = getCallLogViewData(artifact);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error getting attributes for Calllog artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
}
List<AccountPersonaSearcherData> personaSearchDataList = new ArrayList<>();
// update the view with the call log data
if (callLogViewData != null) {
List<AccountPersonaSearcherData> personaSearchDataList = updateView(callLogViewData);
if (!personaSearchDataList.isEmpty()) {
currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
currentAccountFetcher.execute();
} else {
currentAccountFetcher = null;
}
personaSearchDataList.addAll(updateView(callLogViewData));
}
if (!personaSearchDataList.isEmpty()) {
currentAccountFetcher = new PersonaAccountFetcher(artifact, personaSearchDataList, this);
currentAccountFetcher.execute();
} else {
currentAccountFetcher = null;
}
// repaint
this.revalidate();
this.repaint();
}
/**
@ -320,7 +318,7 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
// Display "From" if we have non-local device accounts
if (callLogViewData.getFromAccount() != null) {
CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, this.m_constraints, Bundle.CallLogArtifactViewer_label_from());
// check if this is local account
String accountDisplayString = getAccountDisplayString(callLogViewData.getFromAccount(), callLogViewData);
CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, this.m_constraints, accountDisplayString);
@ -371,8 +369,6 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac
this.setLayout(m_gridBagLayout);
this.revalidate();
this.repaint();
return dataList;
}

View File

@ -130,19 +130,15 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
// Reset the panel.
resetComponent();
if (artifact == null) {
return;
if (artifact != null) {
try {
extractArtifactData(artifact);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
return;
}
updateView();
}
try {
extractArtifactData(artifact);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
return;
}
updateView();
this.setLayout(this.m_gridBagLayout);
this.revalidate();
this.repaint();
@ -164,6 +160,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Extracts data from the artifact to be displayed in the panel.
*
* @param artifact Artifact to show.
*
* @throws TskCoreException
*/
private void extractArtifactData(BlackboardArtifact artifact) throws TskCoreException {
@ -235,7 +232,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Updates the contact image in the view.
*
* @param contactPanelLayout Panel layout.
* @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@ -267,7 +264,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Updates the contact name in the view.
*
* @param contactPanelLayout Panel layout.
* @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@ -294,9 +291,9 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Updates the view by displaying the given list of attributes in the given
* section panel.
*
* @param sectionAttributesList List of attributes to display.
* @param sectionHeader Section name label.
* @param contactPanelLayout Panel layout.
* @param sectionAttributesList List of attributes to display.
* @param sectionHeader Section name label.
* @param contactPanelLayout Panel layout.
* @param contactPanelConstraints Layout constraints.
*
*/
@ -418,12 +415,12 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Displays the given persona in the persona panel.
*
* @param persona Persona to display.
* @param matchNumber Number of matches.
* @param persona Persona to display.
* @param matchNumber Number of matches.
* @param missingAccountsList List of contact accounts this persona may be
* missing.
* @param gridBagLayout Layout to use.
* @param constraints layout constraints.
* missing.
* @param gridBagLayout Layout to use.
* @param constraints layout constraints.
*
* @throws CentralRepoException
*/
@ -567,7 +564,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* @param artifact
*
* @return Image from a TSK_CONTACT artifact or default image if none was
* found or the artifact is not a TSK_CONTACT
* found or the artifact is not a TSK_CONTACT
*/
private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
ImageIcon imageIcon = defaultImage;
@ -617,7 +614,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
* Creates a persona searcher task.
*
* @param accountAttributesList List of attributes that may map to
* accounts.
* accounts.
*/
ContactPersonaSearcherTask(BlackboardArtifact artifact) {
this.artifact = artifact;
@ -647,7 +644,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
}
}
}
Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
if (personaAccounts != null && !personaAccounts.isEmpty()) {
// get personas for the account
@ -716,7 +713,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
/**
* Constructor.
*
* @param personaNameLabel Persona name label.
* @param personaNameLabel Persona name label.
* @param personaActionButton Persona action button.
*/
PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
@ -784,8 +781,8 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac
for (CentralRepoAccount account : contactUniqueAccountsList) {
personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
}
if(contactName != null && contactUniqueAccountsList.isEmpty()) {
if (contactName != null && contactUniqueAccountsList.isEmpty()) {
createPersonaDialog.setStartupPopupMessage(Bundle.ContactArtifactViewer_id_not_found_in_cr(contactName));
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -36,6 +36,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -277,6 +278,8 @@ public class Artifacts {
*/
private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
private final Category category;
private final PropertyChangeListener weakPcl;
/**
* Main constructor.
@ -290,45 +293,50 @@ public class Artifacts {
super();
this.filteringDSObjId = filteringDSObjId;
this.category = category;
}
private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
/**
* This is a stop gap measure until a different way of handling
* the closing of cases is worked out. Currently, remote events
* may be received for a case that is already closed.
*/
try {
Case.getCurrentCaseThrows();
refresh(false);
} catch (NoCurrentCaseException notUsed) {
PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
String eventType = evt.getPropertyName();
if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
/**
* Case is closed, do nothing.
* This is a stop gap measure until a different way of
* handling the closing of cases is worked out. Currently,
* remote events may be received for a case that is already
* closed.
*/
try {
Case.getCurrentCaseThrows();
refresh(false);
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
}
}
};
};
weakPcl = WeakListeners.propertyChange(pcl, null);
}
@Override
protected void addNotify() {
protected void addNotify() {
super.addNotify();
refreshThrottler.registerForIngestModuleEvents();
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Override
protected void removeNotify() {
protected void finalize() throws Throwable {
super.finalize();
refreshThrottler.unregisterEventListener();
IngestManager.getInstance().removeIngestJobEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
typeNodeMap.clear();
}
@ -624,17 +632,21 @@ public class Artifacts {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void onAdd() {
refreshThrottler.registerForIngestModuleEvents();
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected void onRemove() {
refreshThrottler.unregisterEventListener();
IngestManager.getInstance().removeIngestJobEventListener(pcl);
if(refreshThrottler != null) {
refreshThrottler.unregisterEventListener();
}
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
}
@Override

View File

@ -1,6 +1,5 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
@ -20,7 +19,6 @@ package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
@ -32,6 +30,7 @@ import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Node;
import org.openide.util.WeakListeners;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -83,16 +82,18 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
super.addNotify();
Case.addEventTypeSubscriber(EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected void removeNotify() {
super.removeNotify();
Case.removeEventTypeSubscriber(EVENTS_OF_INTEREST, pcl);
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(EVENTS_OF_INTEREST, weakPcl);
}
/**
@ -128,7 +129,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
.sorted()
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(personManager.getHostsForPerson(null))) {
if (CollectionUtils.isNotEmpty(personManager.getHostsWithoutPersons())) {
nodes.add(new PersonGrouping(null));
}
} else {

View File

@ -115,14 +115,15 @@ public abstract class BaseChildFactory<T extends Content> extends ChildFactory.D
isPageSizeChangeEvent = false;
this.filter = filter;
}
@Override
protected void addNotify() {
onAdd();
}
@Override
protected void removeNotify() {
protected void finalize() throws Throwable {
super.finalize();
onRemove();
}

View File

@ -31,6 +31,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -76,15 +77,18 @@ public class DataSourcesNode extends DisplayableItemNode {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(UPDATE_EVTS, pcl);
Case.addEventTypeSubscriber(UPDATE_EVTS, weakPcl);
}
@Override
protected void removeNotify() {
Case.removeEventTypeSubscriber(UPDATE_EVTS, pcl);
protected void finalize() throws Throwable{
Case.removeEventTypeSubscriber(UPDATE_EVTS, weakPcl);
super.finalize();
}
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2020 Basis Technology Corp.
* Copyright 2012-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -37,6 +37,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -313,21 +314,24 @@ public class EmailExtracted implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
emailResults.update();
emailResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
protected void finalize() throws Throwable{
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
emailResults.deleteObserver(this);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -39,6 +39,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -278,21 +279,24 @@ public class HashsetHits implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
hashsetResults.update();
hashsetResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
hashsetResults.deleteObserver(this);
}

View File

@ -66,7 +66,7 @@ public class HostNode extends DisplayableItemNode {
private final Host host;
private final Function<DataSourceGrouping, Node> dataSourceToNode;
/**
* Main constructor.
*
@ -77,7 +77,7 @@ public class HostNode extends DisplayableItemNode {
this.host = host;
this.dataSourceToNode = dataSourceToNode;
}
/**
* Listener for handling DATA_SOURCE_ADDED / HOST_DELETED events.
* A host may have been deleted as part of a merge, which means its data sources could
@ -93,15 +93,19 @@ public class HostNode extends DisplayableItemNode {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(dataSourceAddedPcl, null);
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), dataSourceAddedPcl);
super.addNotify();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), weakPcl);
}
@Override
protected void removeNotify() {
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), dataSourceAddedPcl);
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), weakPcl);
}
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2020 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -39,6 +39,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -271,21 +272,24 @@ public class InterestingHits implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
interestingResults.update();
interestingResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
interestingResults.deleteObserver(this);
}

View File

@ -42,6 +42,7 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -437,7 +438,8 @@ public class KeywordHits implements AutopsyVisitableItem {
}
@Override
protected void removeNotify() {
protected void finalize() throws Throwable {
super.finalize();
keywordResults.deleteObserver(this);
}
@ -504,22 +506,24 @@ public class KeywordHits implements AutopsyVisitableItem {
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
keywordResults.update();
super.addNotify();
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.removeNotify();
protected void finalize() throws Throwable{
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.finalize();
}
@Override

View File

@ -137,19 +137,22 @@ public final class OsAccounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(listener, null);
@Override
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNTS_ADDED), weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.OS_ACCOUNTS_ADDED, Case.Events.OS_ACCOUNTS_DELETED), listener);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
}
@Override
protected void removeNotify() {
Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNTS_ADDED), listener);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
}
@Override
protected boolean createKeys(List<OsAccount> list) {
if (skCase != null) {

View File

@ -92,6 +92,7 @@ public class PersonNode extends DisplayableItemNode {
*/
PersonChildren(Person person) {
this.person = person;
}
/**
@ -111,17 +112,20 @@ public class PersonNode extends DisplayableItemNode {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostAddedDeletedPcl, null);
@Override
protected void addNotify() {
Case.addEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, hostAddedDeletedPcl);
Case.addEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected void removeNotify() {
Case.removeEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, hostAddedDeletedPcl);
protected void finalize() throws Throwable {
super.finalize();
Case.removeEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl);
}
@Override
protected HostNode createNodeForKey(HostGrouping key) {
return key == null ? null : new HostNode(key);

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,6 +33,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -213,6 +214,8 @@ public class Tags implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
/**
* Constructor
@ -221,21 +224,21 @@ public class Tags implements AutopsyVisitableItem {
*/
TagNameNodeFactory(long objId) {
this.filteringDSObjId = objId;
}
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
tagResults.update();
tagResults.addObserver(this);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, weakPcl);
tagResults.deleteObserver(this);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2019 Basis Technology Corp.
* Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -57,6 +57,7 @@ import org.openide.nodes.NodeOp;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
@ -218,8 +219,8 @@ final public class Accounts implements AutopsyVisitableItem {
abstract void handleDataAdded(ModuleDataEvent event);
@Override
protected void removeNotify() {
super.removeNotify();
protected void finalize() throws Throwable {
super.finalize();
reviewStatusBus.unregister(ObservingChildren.this);
}
@ -415,6 +416,8 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Subscribe
@Override
@ -473,18 +476,18 @@ final public class Accounts implements AutopsyVisitableItem {
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.removeNotify();
protected void finalize() throws Throwable {
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.finalize();
}
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.addNotify();
refresh(true);
}
@ -550,21 +553,22 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.addNotify();
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.removeNotify();
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Override
@ -727,6 +731,9 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Subscribe
@Override
@ -739,20 +746,21 @@ final public class Accounts implements AutopsyVisitableItem {
void handleDataAdded(ModuleDataEvent event) {
refresh(true);
}
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.addNotify();
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.removeNotify();
}
@ -881,21 +889,23 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.addNotify();
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.removeNotify();
protected void finalize() throws Throwable {
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Subscribe
@ -1095,21 +1105,23 @@ final public class Accounts implements AutopsyVisitableItem {
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
@Override
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
super.addNotify();
}
@Override
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(pcl);
IngestManager.getInstance().removeIngestModuleEventListener(pcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl);
super.removeNotify();
protected void finalize() throws Throwable{
super.finalize();
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Subscribe

View File

@ -31,6 +31,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.AbstractAction;
import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.AbstractNode;
import org.openide.explorer.ExplorerManager;
import org.openide.explorer.view.TreeView;
@ -84,7 +85,7 @@ public class ViewContextAction extends AbstractAction {
* parent of the content, selecting the parent in the tree view, then
* selecting the content in the results view.
*
* @param displayName The display name for the action.
* @param displayName The display name for the action.
* @param artifactNode The artifact node for the artifact.
*/
public ViewContextAction(String displayName, BlackboardArtifactNode artifactNode) {
@ -106,9 +107,9 @@ public class ViewContextAction extends AbstractAction {
* parent of the content, selecting the parent in the tree view, then
* selecting the content in the results view.
*
* @param displayName The display name for the action.
* @param displayName The display name for the action.
* @param fileSystemContentNode The file system content node for the
* content.
* content.
*/
public ViewContextAction(String displayName, AbstractFsContentNode<? extends AbstractFile> fileSystemContentNode) {
super(displayName);
@ -121,9 +122,9 @@ public class ViewContextAction extends AbstractAction {
* content, selecting the parent in the tree view, then selecting the
* content in the results view.
*
* @param displayName The display name for the action.
* @param displayName The display name for the action.
* @param abstractAbstractFileNode The AbstractAbstractFileNode node for the
* content.
* content.
*/
public ViewContextAction(String displayName, AbstractAbstractFileNode<? extends AbstractFile> abstractAbstractFileNode) {
super(displayName);
@ -137,7 +138,7 @@ public class ViewContextAction extends AbstractAction {
* content in the results view.
*
* @param displayName The display name for the action.
* @param content The content.
* @param content The content.
*/
public ViewContextAction(String displayName, Content content) {
super(displayName);
@ -149,7 +150,7 @@ public class ViewContextAction extends AbstractAction {
* branch of the tree view to the level of the parent of the content,
* selecting the parent in the tree view, then selecting the content in the
* results view.
*
*
* NOTE: This code will likely need updating in the event that the structure
* of the nodes is changed (i.e. adding parent levels). Places to look when
* changing node structure include:
@ -168,176 +169,224 @@ public class ViewContextAction extends AbstractAction {
public void actionPerformed(ActionEvent event) {
EventQueue.invokeLater(() -> {
/*
* Get the parent content for the content to be selected in the
* results view. If the parent content is null, then the specified
* content is a data source, and the parent tree view node is the
* "Data Sources" node. Otherwise, the tree view needs to be
* searched to find the parent treeview node.
*/
Content parentContent = null;
try {
parentContent = content.getParent();
} catch (TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindDirectory());
logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
return;
}
if ((parentContent != null)
&& (parentContent instanceof UnsupportedContent)) {
Content parentContent = getParentContent(this.content);
if ((parentContent != null) && (parentContent instanceof UnsupportedContent)) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent());
logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS
return;
}
/*
* Get the "Data Sources" node from the tree view.
*/
// Get the "Data Sources" node from the tree view.
DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance();
ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager();
Node parentTreeViewNode = null;
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { // 'Group by Data Source' view
SleuthkitCase skCase;
String dsname;
try {
// get the objid/name of the datasource of the selected content.
skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
long contentDSObjid = content.getDataSource().getId();
DataSource datasource = skCase.getDataSource(contentDSObjid);
dsname = datasource.getName();
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
if (null != parentContent) {
// the tree view needs to be searched to find the parent treeview node.
/* NOTE: we can't do a lookup by data source name here, becase if there
are multiple data sources with the same name, then "getChildren().findChild(dsname)"
simply returns the first one that it finds. Instead we have to loop over all
data sources with that name, and make sure we find the correct one.
*/
List<Node> dataSourceLevelNodes = Stream.of(rootChildren.getNodes())
.flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream())
.collect(Collectors.toList());
for (Node treeNode : dataSourceLevelNodes) {
// in the root, look for a data source node with the name of interest
if (!(treeNode.getName().equals(dsname))) {
continue;
}
// for this data source, get the "Data Sources" child node
Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier());
// check whether this is the data source we are looking for
parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
if (parentTreeViewNode != null) {
// found the data source node
break;
}
}
} else {
/* If the parent content is null, then the specified
* content is a data source, and the parent tree view node is the
* "Data Sources" node. */
Node datasourceGroupingNode = rootChildren.findChild(dsname);
if (!Objects.isNull(datasourceGroupingNode)) {
Children dsChildren = datasourceGroupingNode.getChildren();
parentTreeViewNode = dsChildren.findChild(DataSourceFilesNode.getNameIdentifier());
}
}
if (parentTreeViewNode == null) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
return;
}
} catch (NoCurrentCaseException | TskDataException | TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
return;
}
} else { // Classic view
// Start the search at the DataSourcesNode
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(DataSourcesNode.getNameIdentifier());
if (rootDsNode != null) {
for (Node dataSourceLevelNode : getDataSourceLevelNodes(rootDsNode)) {
DataSource dataSource = dataSourceLevelNode.getLookup().lookup(DataSource.class);
if (dataSource != null) {
// the tree view needs to be searched to find the parent treeview node.
Node potentialParentTreeViewNode = findParentNodeInTree(parentContent, dataSourceLevelNode);
if (potentialParentTreeViewNode != null) {
parentTreeViewNode = potentialParentTreeViewNode;
break;
}
}
}
if (parentContent != null) {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
parentTreeViewNode = getParentNodeGroupedByPersonHost(treeViewExplorerMgr, parentContent);
} else {
parentTreeViewNode = getParentNodeGroupedByDataSource(treeViewExplorerMgr, parentContent);
}
}
/*
* Set the child selection info of the parent tree node, then select
* the parent node in the tree view. The results view will retrieve
* this selection info and use it to complete this action when the
* tree view top component responds to the selection of the parent
* node by pushing it into the results view top component.
*/
DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) parentTreeViewNode).getOriginal();
undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(content));
if (content instanceof BlackboardArtifact) {
BlackboardArtifact artifact = ((BlackboardArtifact) content);
long associatedId = artifact.getObjectID();
try {
Content associatedFileContent = artifact.getSleuthkitCase().getContentById(associatedId);
undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(associatedFileContent));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not find associated content from artifact with id %d", artifact.getId());
}
// if no node is found, report error and do nothing
if (parentTreeViewNode == null) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree."); //NON-NLS
return;
}
TreeView treeView = treeViewTopComponent.getTree();
treeView.expandNode(parentTreeViewNode);
if (treeViewTopComponent.getSelectedNode().equals(parentTreeViewNode)) {
//In the case where our tree view already has the destination directory selected
//due to an optimization in the ExplorerManager.setExploredContextAndSelection method
//the property change we listen for to call DirectoryTreeTopComponent.respondSelection
//will not be sent so we call it manually ourselves after making
//the directory listing the active tab.
treeViewTopComponent.setDirectoryListingActive();
treeViewTopComponent.respondSelection(treeViewExplorerMgr.getSelectedNodes(), new Node[]{parentTreeViewNode});
} else {
try {
treeViewExplorerMgr.setExploredContextAndSelection(parentTreeViewNode, new Node[]{parentTreeViewNode});
} catch (PropertyVetoException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotSelectDirectory());
logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS
}
}
setNodeSelection(this.content, parentTreeViewNode, treeViewTopComponent, treeViewExplorerMgr);
});
}
/**
* Get the parent content for the content to be selected in the results
* view. If the parent content is null, then the specified content is a data
* source, and the parent tree view node is the "Data Sources" node.
* Otherwise, the tree view needs to be searched to find the parent treeview
* node.
*
* @param content The content whose parent will be returned. If this item is
* a datasource, it will be returned.
*
* @return The content if content is a data source or the parent of this
* content.
*/
private Content getParentContent(Content content) {
try {
return (content instanceof DataSource)
? content
: content.getParent();
} catch (TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindDirectory());
logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
return null;
}
}
/**
* Returns the node in the tree related to the parentContent or null if
* can't be found. This method should be used when view is grouped by data
* source.
*
* @param treeViewExplorerMgr The explorer manager.
* @param parentContent The content whose equivalent node will be
* returned if found.
*
* @return The node if found or null.
*/
private Node getParentNodeGroupedByDataSource(ExplorerManager treeViewExplorerMgr, Content parentContent) {
// Classic view
// Start the search at the DataSourcesNode
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
Node rootDsNode = rootChildren == null ? null : rootChildren.findChild(DataSourcesNode.getNameIdentifier());
if (rootDsNode != null) {
for (Node dataSourceLevelNode : getDataSourceLevelNodes(rootDsNode)) {
DataSource dataSource = dataSourceLevelNode.getLookup().lookup(DataSource.class);
if (dataSource != null) {
// the tree view needs to be searched to find the parent treeview node.
Node potentialParentTreeViewNode = findParentNodeInTree(parentContent, dataSourceLevelNode);
if (potentialParentTreeViewNode != null) {
return potentialParentTreeViewNode;
}
}
}
}
return null;
}
/**
* Returns the node in the tree related to the parentContent or null if
* can't be found. This method should be used when view is grouped by
* hosts/persons.
*
* @param treeViewExplorerMgr The explorer manager.
* @param parentContent The content whose equivalent node will be
* returned if found.
*
* @return The node if found or null.
*/
private Node getParentNodeGroupedByPersonHost(ExplorerManager treeViewExplorerMgr, Content parentContent) {
// 'Group by Data Source' view
SleuthkitCase skCase;
String dsname;
try {
// get the objid/name of the datasource of the selected content.
skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
long contentDSObjid = parentContent.getDataSource().getId();
DataSource datasource = skCase.getDataSource(contentDSObjid);
dsname = datasource.getName();
Children rootChildren = treeViewExplorerMgr.getRootContext().getChildren();
// the tree view needs to be searched to find the parent treeview node.
/* NOTE: we can't do a lookup by data source name here, becase if there
are multiple data sources with the same name, then "getChildren().findChild(dsname)"
simply returns the first one that it finds. Instead we have to loop over all
data sources with that name, and make sure we find the correct one.
*/
List<Node> dataSourceLevelNodes = Stream.of(rootChildren.getNodes(true))
.flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream())
.collect(Collectors.toList());
for (Node treeNode : dataSourceLevelNodes) {
// in the root, look for a data source node with the name of interest
if (!(treeNode.getName().equals(dsname))) {
continue;
}
// for this data source, get the "Data Sources" child node
Node datasourceGroupingNode = treeNode.getChildren().findChild(DataSourceFilesNode.getNameIdentifier());
// check whether this is the data source we are looking for
Node parentTreeViewNode = findParentNodeInTree(parentContent, datasourceGroupingNode);
if (parentTreeViewNode != null) {
// found the data source node
return parentTreeViewNode;
}
}
} catch (NoCurrentCaseException | TskDataException | TskCoreException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode());
logger.log(Level.SEVERE, "Failed to locate data source node in tree.", ex); //NON-NLS
}
return null;
}
/**
* Set the node selection in the tree.
* @param content The content to select.
* @param parentTreeViewNode The node that is the parent of the content.
* @param treeViewTopComponent The DirectoryTreeTopComponent.
* @param treeViewExplorerMgr The ExplorerManager.
*/
private void setNodeSelection(Content content, Node parentTreeViewNode, DirectoryTreeTopComponent treeViewTopComponent, ExplorerManager treeViewExplorerMgr) {
/*
* Set the child selection info of the parent tree node, then select
* the parent node in the tree view. The results view will retrieve
* this selection info and use it to complete this action when the
* tree view top component responds to the selection of the parent
* node by pushing it into the results view top component.
*/
DisplayableItemNode undecoratedParentNode = (DisplayableItemNode) ((DirectoryTreeFilterNode) parentTreeViewNode).getOriginal();
undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(content));
if (content instanceof BlackboardArtifact) {
BlackboardArtifact artifact = ((BlackboardArtifact) content);
long associatedId = artifact.getObjectID();
try {
Content associatedFileContent = artifact.getSleuthkitCase().getContentById(associatedId);
undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(associatedFileContent));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not find associated content from artifact with id %d", artifact.getId());
}
}
TreeView treeView = treeViewTopComponent.getTree();
treeView.expandNode(parentTreeViewNode);
if (treeViewTopComponent.getSelectedNode().equals(parentTreeViewNode)) {
//In the case where our tree view already has the destination directory selected
//due to an optimization in the ExplorerManager.setExploredContextAndSelection method
//the property change we listen for to call DirectoryTreeTopComponent.respondSelection
//will not be sent so we call it manually ourselves after making
//the directory listing the active tab.
treeViewTopComponent.setDirectoryListingActive();
treeViewTopComponent.respondSelection(treeViewExplorerMgr.getSelectedNodes(), new Node[]{parentTreeViewNode});
} else {
try {
treeViewExplorerMgr.setExploredContextAndSelection(parentTreeViewNode, new Node[]{parentTreeViewNode});
} catch (PropertyVetoException ex) {
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotSelectDirectory());
logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS
}
}
}
/**
* If the node has lookup of host or person, returns children. If not, just
* returns itself.
*
* @param node The node.
*
* @return The child nodes that are at the data source level.
*/
private List<Node> getDataSourceLevelNodes(Node node) {
if (node == null) {
return Collections.emptyList();
} else if (node.getLookup().lookup(Host.class) != null ||
node.getLookup().lookup(Person.class) != null ||
DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class)) ||
PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
} else if (node.getLookup().lookup(Host.class) != null
|| node.getLookup().lookup(Person.class) != null
|| DataSourcesNode.getNameIdentifier().equals(node.getLookup().lookup(String.class))
|| PersonNode.getUnknownPersonId().equals(node.getLookup().lookup(String.class))) {
Children children = node.getChildren();
Node[] childNodes = children == null ? null : children.getNodes();
Node[] childNodes = children == null ? null : children.getNodes(true);
if (childNodes == null) {
return Collections.emptyList();
}
return Stream.of(node.getChildren().getNodes())
return Stream.of(node.getChildren().getNodes(true))
.flatMap(parent -> getDataSourceLevelNodes(parent).stream())
.collect(Collectors.toList());
} else {
@ -350,7 +399,8 @@ public class ViewContextAction extends AbstractAction {
* of the specified content.
*
* @param parentContent parent content for the content to be searched for
* @param node Node tree to search
* @param node Node tree to search
*
* @return Node object of the matching parent, NULL if not found
*/
private Node findParentNodeInTree(Content parentContent, Node node) {
@ -377,6 +427,11 @@ public class ViewContextAction extends AbstractAction {
Node dummyRootNode = new DirectoryTreeFilterNode(new AbstractNode(new RootContentChildren(contentBranch)), true);
Children ancestorChildren = dummyRootNode.getChildren();
// if content is the data source provided, return that.
if (ancestorChildren.getNodesCount() == 1 && StringUtils.equals(ancestorChildren.getNodeAt(0).getName(), node.getName())) {
return node;
}
/*
* Search the tree for the parent node. Note that this algorithm
* simply discards "extra" ancestor nodes not shown in the tree,
@ -387,8 +442,9 @@ public class ViewContextAction extends AbstractAction {
Node parentTreeViewNode = null;
for (int i = 0; i < ancestorChildren.getNodesCount(); i++) {
Node ancestorNode = ancestorChildren.getNodeAt(i);
for (int j = 0; j < treeNodeChildren.getNodesCount(); j++) {
Node treeNode = treeNodeChildren.getNodeAt(j);
Node[] treeNodeChilds = treeNodeChildren.getNodes(true);
for (int j = 0; j < treeNodeChilds.length; j++) {
Node treeNode = treeNodeChilds[j];
if (ancestorNode.getName().equals(treeNode.getName())) {
parentTreeViewNode = treeNode;
treeNodeChildren = treeNode.getChildren();