From a14da8b04bb79eab19d1ff513ecaac196ab3898a Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 26 May 2021 13:29:57 -0400 Subject: [PATCH 01/18] Make listeners in ChildFactory.Detachable weak --- .../autopsy/datamodel/Artifacts.java | 77 ++++++++------- .../datamodel/AutopsyTreeChildFactory.java | 19 ++-- .../autopsy/datamodel/BaseChildFactory.java | 5 +- .../datamodel/DataSourcesByTypeNode.java | 13 ++- .../autopsy/datamodel/EmailExtracted.java | 23 +++-- .../autopsy/datamodel/HashsetHits.java | 23 +++-- .../sleuthkit/autopsy/datamodel/HostNode.java | 33 ++++--- .../autopsy/datamodel/InterestingHits.java | 25 ++--- .../autopsy/datamodel/KeywordHits.java | 8 +- .../autopsy/datamodel/OsAccounts.java | 16 ++-- .../autopsy/datamodel/PersonGroupingNode.java | 13 ++- .../org/sleuthkit/autopsy/datamodel/Tags.java | 21 ++-- .../autopsy/datamodel/accounts/Accounts.java | 95 +++++++++---------- 13 files changed, 196 insertions(+), 175 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index d39bef3ee9..6e207b9458 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.lang.ref.WeakReference; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -36,6 +37,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; @@ -276,6 +278,8 @@ public class Artifacts { */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private final Category category; + + private final PropertyChangeListener weakPcl; /** * Main constructor. @@ -289,45 +293,46 @@ 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. + */ + } } - } - }; + }; - @Override - protected void addNotify() { + weakPcl = WeakListeners.propertyChange(pcl, null); + 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(); } @@ -623,17 +628,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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 845591e261..5b9302d357 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,6 +31,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; @@ -75,17 +76,17 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable 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(); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesByTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesByTypeNode.java index 1fab7774c7..322a18428e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesByTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesByTypeNode.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; +import org.openide.util.WeakListeners; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -71,15 +72,17 @@ public class DataSourcesByTypeNode extends DisplayableItemNode { } } }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - @Override - protected void addNotify() { - Case.addEventTypeSubscriber(UPDATE_EVTS, pcl); + public DataSourcesByTypeChildren() { + Case.addEventTypeSubscriber(UPDATE_EVTS, weakPcl); } @Override - protected void removeNotify() { - Case.removeEventTypeSubscriber(UPDATE_EVTS, pcl); + public void finalize() throws Throwable { + super.finalize(); + Case.removeEventTypeSubscriber(UPDATE_EVTS, weakPcl); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 357f6ec153..8a621bf245 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2020 Basis Technology Corp. + * Copyright 2012-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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; @@ -312,21 +313,23 @@ 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); + AccountFactory() { + 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); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index 5906b01a78..5aa6c0b570 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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; @@ -277,21 +278,23 @@ 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); + HashsetNameFactory() { + 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); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java index a98bdb61dd..323536df9e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HostNode.java @@ -65,18 +65,7 @@ public class HostNode extends DisplayableItemNode { private final Host host; private final Function dataSourceToNode; - - /** - * Main constructor. - * - * @param dataSourceToItem Converts a data source to a node. - * @param host The host. - */ - HostGroupingChildren(Function dataSourceToNode, Host host) { - 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 @@ -92,15 +81,25 @@ 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); + /** + * Main constructor. + * + * @param dataSourceToItem Converts a data source to a node. + * @param host The host. + */ + HostGroupingChildren(Function dataSourceToNode, Host host) { + this.host = host; + this.dataSourceToNode = dataSourceToNode; + 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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 22525854ca..41b90268a2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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; @@ -270,21 +271,23 @@ public class InterestingHits implements AutopsyVisitableItem { } } }; - - @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); + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); + + SetNameFactory() { + 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); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index eab8a07d3a..b55fc9353a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2020 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -429,13 +429,13 @@ public class KeywordHits implements AutopsyVisitableItem { private abstract class DetachableObserverChildFactory extends ChildFactory.Detachable implements Observer { - @Override - protected void addNotify() { + DetachableObserverChildFactory() { keywordResults.addObserver(this); } @Override - protected void removeNotify() { + protected void finalize() throws Throwable { + super.finalize(); keywordResults.deleteObserver(this); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java index 170251bd13..950565a5f2 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java @@ -136,17 +136,19 @@ public final class OsAccounts implements AutopsyVisitableItem { } } }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(listener, null); - @Override - protected void addNotify() { - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.OS_ACCOUNT_ADDED, Case.Events.OS_ACCOUNT_REMOVED), listener); - Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener); + OsAccountNodeFactory () { + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.OS_ACCOUNT_ADDED, Case.Events.OS_ACCOUNT_REMOVED), weakPcl); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); } @Override - protected void removeNotify() { - Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener); - Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener); + protected void finalize() throws Throwable { + super.finalize(); + Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), weakPcl); + Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/PersonGroupingNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/PersonGroupingNode.java index 4f12779ee8..0655383c40 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/PersonGroupingNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/PersonGroupingNode.java @@ -86,6 +86,7 @@ public class PersonGroupingNode extends DisplayableItemNode { */ PersonChildren(Person person) { this.person = person; + Case.addEventTypeSubscriber(CHILD_EVENTS, weakPcl); } /** @@ -100,15 +101,13 @@ public class PersonGroupingNode extends DisplayableItemNode { } } }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostAddedDeletedPcl, null); @Override - protected void addNotify() { - Case.addEventTypeSubscriber(CHILD_EVENTS, hostAddedDeletedPcl); - } - - @Override - protected void removeNotify() { - Case.removeEventTypeSubscriber(CHILD_EVENTS, hostAddedDeletedPcl); + protected void finalize() throws Throwable { + super.finalize(); + Case.removeEventTypeSubscriber(CHILD_EVENTS, weakPcl); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 6fa6487b5e..2816b2b2b6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2019 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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,17 @@ 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); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 18136db99e..1f186aae2c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2019 Basis Technology Corp. + * Copyright 2011-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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; @@ -496,6 +497,9 @@ final public class Accounts implements AutopsyVisitableItem { private DefaultAccountFactory(Account.Type accountType) { this.accountType = accountType; + 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); } private final PropertyChangeListener pcl = new PropertyChangeListener() { @@ -549,21 +553,15 @@ 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(); - } - - @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 @@ -726,6 +724,14 @@ final public class Accounts implements AutopsyVisitableItem { } } }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); + + ViewModeFactory() { + 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); + } @Subscribe @Override @@ -740,18 +746,11 @@ final public class Accounts implements AutopsyVisitableItem { } @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(); - } - - @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(); } @@ -880,21 +879,21 @@ 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(); + FileWithCCNFactory() { + 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); } @Subscribe @@ -1094,21 +1093,21 @@ 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(); + BINFactory() { + 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); } @Subscribe From b46e1cc35d7a88b68db05045c7b88144adc54e32 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Thu, 3 Jun 2021 16:11:56 -0400 Subject: [PATCH 02/18] Minor changed to clean up the return of the addNotify methods --- .../autopsy/datamodel/Artifacts.java | 3 ++- .../datamodel/AutopsyTreeChildFactory.java | 12 +++++----- .../sleuthkit/autopsy/datamodel/HostNode.java | 23 ++++++++++--------- .../autopsy/datamodel/PersonNode.java | 11 ++++----- .../autopsy/datamodel/accounts/Accounts.java | 6 ++++- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java index a8c1c08b76..cd0b03fd98 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Artifacts.java @@ -324,7 +324,8 @@ public class Artifacts { } @Override - protected void addNotify() { + protected void addNotify() { + super.addNotify(); refreshThrottler.registerForIngestModuleEvents(); IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 1393a6ab4d..1f3356caf7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -84,17 +84,17 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable dataSourceToNode; + /** + * Main constructor. + * + * @param dataSourceToItem Converts a data source to a node. + * @param host The host. + */ + HostGroupingChildren(Function dataSourceToNode, Host host) { + 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 @@ -84,20 +95,10 @@ public class HostNode extends DisplayableItemNode { }; private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(dataSourceAddedPcl, null); - - /** - * Main constructor. - * - * @param dataSourceToItem Converts a data source to a node. - * @param host The host. - */ - HostGroupingChildren(Function dataSourceToNode, Host host) { - this.host = host; - this.dataSourceToNode = dataSourceToNode; - } @Override protected void addNotify() { + super.addNotify(); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.HOSTS_DELETED), weakPcl); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java index 3820514219..ce55b25560 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/PersonNode.java @@ -115,18 +115,17 @@ public class PersonNode extends DisplayableItemNode { private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(hostAddedDeletedPcl, null); + @Override + protected void addNotify() { + Case.addEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl); + } + @Override protected void finalize() throws Throwable { super.finalize(); Case.removeEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl); } - @Override - protected void addNotify() { - Case.addEventTypeSubscriber(HOST_EVENTS_OF_INTEREST, weakPcl); - } - - @Override protected HostNode createNodeForKey(HostGrouping key) { return key == null ? null : new HostNode(key); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 5e82a23009..7b2e1f5147 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -750,6 +750,7 @@ final public class Accounts implements AutopsyVisitableItem { 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 @@ -894,6 +895,7 @@ final public class Accounts implements AutopsyVisitableItem { 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 @@ -1104,10 +1106,12 @@ final public class Accounts implements AutopsyVisitableItem { private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); - BINFactory() { + @Override + protected void 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); + super.addNotify(); } @Override From 24cbab97e16ae53bf96ad0da46e2fb078f37dd41 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jun 2021 15:07:14 -0400 Subject: [PATCH 03/18] 7639 refresh ingest jobs panel in a swing worker --- .../casemodule/IngestJobInfoPanel.java | 57 ++++++++++++------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 5fe65783b0..c28d36757e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -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,7 +53,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED); private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE); private static final int EXTRA_ROW_HEIGHT = 4; - private List ingestJobs; + private List ingestJobs = new ArrayList<>(); private final List ingestJobsForSelectedDataSource = new ArrayList<>(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); private IngestModuleTableModel ingestModuleTableModel = new IngestModuleTableModel(null); @@ -76,19 +78,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 +104,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { }); ingestJobTable.setRowHeight(ingestJobTable.getRowHeight() + EXTRA_ROW_HEIGHT); ingestModuleTable.setRowHeight(ingestModuleTable.getRowHeight() + EXTRA_ROW_HEIGHT); - + } /** @@ -133,22 +135,39 @@ 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); - } + new SwingWorker() { - } 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); - } + @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); + } + } + }.execute(); } - + /** * Reset the panel. */ From cf3cb5a0b26f04291e6a9a4129b2d883cbaf5c26 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 7 Jun 2021 15:08:28 -0400 Subject: [PATCH 04/18] 7639 formatting --- .../org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index c28d36757e..6e1df2b8c0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -136,7 +136,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { */ private void refresh() { new SwingWorker() { - + @Override protected Boolean doInBackground() throws Exception { ingestJobs.clear(); From ffce7d10b401b033af6f8be3a81e11e642e8b161 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Jun 2021 12:25:47 -0400 Subject: [PATCH 05/18] 7653 eliminate null check preventing proper reset --- .../relationships/CallLogViewer.java | 2 +- .../relationships/RelationshipBrowser.java | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java index 21d7deb8bd..199a19e136 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java index 229a0067de..0894fa3b1b 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java @@ -37,15 +37,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 +95,10 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider }// //GEN-END:initComponents private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged - if(currentSelection != null) { - ((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection); - } - + ((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection); Component selectedComponent = tabPane.getSelectedComponent(); - if(selectedComponent instanceof Lookup.Provider) { - Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup(); + if (selectedComponent instanceof Lookup.Provider) { + Lookup lookup = ((Lookup.Provider) selectedComponent).getLookup(); proxyLookup.setNewLookups(lookup); } }//GEN-LAST:event_tabPaneStateChanged From 15885df3865dd0897c3aa53e7b5dafeb5c2e4a86 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Jun 2021 12:26:53 -0400 Subject: [PATCH 06/18] 7653 formatting --- .../autopsy/communications/relationships/CallLogViewer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java index 199a19e136..3fe8ec204e 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java @@ -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()); } @@ -229,7 +229,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; From 68ed24c500bea88b857ce0490353e1bfcb0de299 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Jun 2021 17:24:06 -0400 Subject: [PATCH 07/18] 7653 fix refreshing of callogs,media, and contacts when no info --- .../relationships/CallLogViewer.java | 2 + .../ContactsChildNodeFactory.java | 20 ++++--- .../relationships/ContactsViewer.java | 2 +- .../relationships/MediaViewer.java | 21 ++++---- .../relationships/RelationshipBrowser.java | 21 +++++--- .../CallLogArtifactViewer.java | 26 ++++----- .../ContactArtifactViewer.java | 54 +++++++++---------- 7 files changed, 75 insertions(+), 71 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java index 3fe8ec204e..664f50ce34 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java index 28666c8fdd..ab980ee101 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsChildNodeFactory.java @@ -35,7 +35,8 @@ import org.sleuthkit.datamodel.TskCoreException; /** * ChildFactory for ContactNodes. */ -final class ContactsChildNodeFactory extends ChildFactory{ +final class ContactsChildNodeFactory extends ChildFactory { + private static final Logger logger = Logger.getLogger(ContactsChildNodeFactory.class.getName()); private SelectionInfo selectionInfo; @@ -47,12 +48,13 @@ final class ContactsChildNodeFactory extends ChildFactory{ * 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{ /** * 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 list) { - - if(selectionInfo == null) { + + if (selectionInfo == null) { return true; } @@ -80,7 +84,7 @@ final class ContactsChildNodeFactory extends ChildFactory{ 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; diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java index 1d11b3ef6d..141dc45cd1 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java @@ -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); } diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java index daffdafb81..7bd5330400 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java @@ -79,7 +79,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> { if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { handleNodeSelectionChange(); - } + } }); thumbnailViewer.resetComponent(); @@ -99,18 +99,19 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM public void setSelectionInfo(SelectionInfo info) { Set relationshipSources; Set 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())); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java index 0894fa3b1b..3de88f4176 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java @@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; * */ public final class RelationshipBrowser extends JPanel implements Lookup.Provider { - + private SelectionInfo currentSelection; private final ModifiableProxyLookup proxyLookup; @@ -37,15 +37,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,10 +95,15 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider }// //GEN-END:initComponents private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged - ((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(null); + //set new values when avaialable + if (currentSelection != null) { + viewer.setSelectionInfo(currentSelection); + } + if (viewer instanceof Lookup.Provider) { + Lookup lookup = ((Lookup.Provider) viewer).getLookup(); proxyLookup.setNewLookups(lookup); } }//GEN-LAST:event_tabPaneStateChanged diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index 8d27c6c5be..af33ff1d59 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -93,29 +93,27 @@ 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 personaSearchDataList = new ArrayList<>(); // update the view with the call log data if (callLogViewData != null) { - List 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(); } /** @@ -315,7 +313,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); @@ -366,8 +364,6 @@ public class CallLogArtifactViewer extends javax.swing.JPanel implements Artifac this.setLayout(m_gridBagLayout); this.revalidate(); - this.repaint(); - return dataList; } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index b17263a26d..c5f9b65ab2 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -41,7 +41,6 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.SwingWorker; import org.apache.commons.lang.StringUtils; @@ -129,19 +128,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(); @@ -163,6 +158,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 { @@ -234,7 +230,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. * */ @@ -262,7 +258,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. * */ @@ -289,9 +285,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. * */ @@ -412,12 +408,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 */ @@ -560,7 +556,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; @@ -610,7 +606,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; @@ -640,7 +636,7 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac } } } - + Collection personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account); if (personaAccounts != null && !personaAccounts.isEmpty()) { // get personas for the account @@ -709,7 +705,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) { @@ -777,8 +773,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)); } From 7862ca475185d0249bed3e49e4c72b4e95da0823 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 9 Jun 2021 17:30:16 -0400 Subject: [PATCH 08/18] 7635 clean up --- .../relationships/CallLogViewer.java | 2 +- .../relationships/ContactsViewer.java | 2 +- .../relationships/MediaViewer.java | 4 ++-- .../relationships/RelationshipBrowser.java | 19 +++++++------------ .../CallLogArtifactViewer.java | 2 +- 5 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java index 664f50ce34..f2b99df0dd 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/CallLogViewer.java @@ -166,7 +166,7 @@ final class CallLogViewer extends javax.swing.JPanel implements RelationshipsVie public void setSelectionInfo(SelectionInfo info) { callLogDataViewer.setNode(null); nodeFactory.refresh(info); - + } @Override diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java index 141dc45cd1..6366d4e517 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java index 7bd5330400..63988b200d 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -79,7 +79,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> { if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) { handleNodeSelectionChange(); - } + } }); thumbnailViewer.resetComponent(); diff --git a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java index 3de88f4176..8910472295 100755 --- a/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/communications/relationships/RelationshipBrowser.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2019 Basis Technology Corp. + * Copyright 2019-2021 Basis Technology Corp. * Contact: carrier sleuthkit 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; @@ -28,7 +27,7 @@ import org.sleuthkit.autopsy.communications.ModifiableProxyLookup; * */ public final class RelationshipBrowser extends JPanel implements Lookup.Provider { - + private SelectionInfo currentSelection; private final ModifiableProxyLookup proxyLookup; @@ -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); @@ -97,13 +96,9 @@ public final class RelationshipBrowser extends JPanel implements Lookup.Provider private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged RelationshipsViewer viewer = ((RelationshipsViewer) tabPane.getSelectedComponent()); //clear old values - viewer.setSelectionInfo(null); - //set new values when avaialable - if (currentSelection != null) { - viewer.setSelectionInfo(currentSelection); - } + viewer.setSelectionInfo(currentSelection); if (viewer instanceof Lookup.Provider) { - Lookup lookup = ((Lookup.Provider) viewer).getLookup(); + Lookup lookup = viewer.getLookup(); proxyLookup.setNewLookups(lookup); } }//GEN-LAST:event_tabPaneStateChanged diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java index af33ff1d59..8393f39dfc 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/CallLogArtifactViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 4af1a2f578d99766fa0cf7732331f5f5251e2d39 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Mon, 14 Jun 2021 14:16:37 -0400 Subject: [PATCH 09/18] Updated a few more locations to use weak references --- .../autopsy/datamodel/DataSourcesNode.java | 10 ++++++--- .../autopsy/datamodel/KeywordHits.java | 19 +++++++++------- .../autopsy/datamodel/accounts/Accounts.java | 22 ++++++++++--------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index c5fae53c03..c2f63d5787 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 5d8976b77d..4406944fa3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -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; @@ -505,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 diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java index 7b2e1f5147..bf7ee1caba 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/accounts/Accounts.java @@ -219,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); } @@ -416,6 +416,8 @@ final public class Accounts implements AutopsyVisitableItem { } } }; + + private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null); @Subscribe @Override @@ -474,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); } From 637c4571f6bdb097472dfd6f87ee301e8dc5623c Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Mon, 14 Jun 2021 14:51:50 -0400 Subject: [PATCH 10/18] bug fix --- .../autopsy/directorytree/ViewContextAction.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index c8f5848243..f3e73f1ff8 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -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; @@ -275,6 +276,11 @@ public class ViewContextAction extends AbstractAction { } } } + + // if no node is found, do nothing + if (parentTreeViewNode == null) { + return; + } /* * Set the child selection info of the parent tree node, then select @@ -377,6 +383,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, From a42cf4eb638051c06cfd82e7d4b0413c705936b7 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Jun 2021 14:11:58 -0400 Subject: [PATCH 11/18] refactoring --- .../directorytree/ViewContextAction.java | 286 +++++++++--------- 1 file changed, 148 insertions(+), 138 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index f3e73f1ff8..2c07c8f8df 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -169,159 +170,168 @@ 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; - } + Content parentContent = getParentContent(this.content); - if ((parentContent != null) - && (parentContent instanceof UnsupportedContent)) { + 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 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); + } } - // if no node is found, do nothing + // 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; } - /* - * 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 - } - } + setNodeSelection(this.content, parentTreeViewNode, treeViewTopComponent, treeViewExplorerMgr); }); } + + private Content getParentContent(Content content) { + /* + * 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. + */ + try { + Content parent = content.getParent(); + if (parent == null && content instanceof DataSource) { + parent = content; + } + return parent; + } 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; + } + } + + + 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; + } + + 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 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 + 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; + } + + + 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 From 7f2ffe526a4eb518d22df554a3df8d32bc5314ac Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Jun 2021 14:25:24 -0400 Subject: [PATCH 12/18] no person hosts fix --- .../sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index 282ed83418..775afec6a4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -128,7 +128,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable Date: Tue, 15 Jun 2021 15:01:27 -0400 Subject: [PATCH 13/18] commenting --- .../directorytree/ViewContextAction.java | 121 +++++++++++------- 1 file changed, 77 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 2c07c8f8df..7dcbcf85de 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -26,7 +26,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -86,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) { @@ -108,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 fileSystemContentNode) { super(displayName); @@ -123,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 abstractAbstractFileNode) { super(displayName); @@ -139,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); @@ -151,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: @@ -171,25 +170,25 @@ public class ViewContextAction extends AbstractAction { EventQueue.invokeLater(() -> { 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 } - + // Get the "Data Sources" node from the tree view. DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); - + Node parentTreeViewNode = null; if (parentContent != null) { - if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { + if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { parentTreeViewNode = getParentNodeGroupedByPersonHost(treeViewExplorerMgr, parentContent); - } else { + } else { parentTreeViewNode = getParentNodeGroupedByDataSource(treeViewExplorerMgr, parentContent); - } + } } - + // if no node is found, report error and do nothing if (parentTreeViewNode == null) { MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotFindNode()); @@ -200,29 +199,44 @@ public class ViewContextAction extends AbstractAction { 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) { - /* - * 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. - */ + try { - Content parent = content.getParent(); - if (parent == null && content instanceof DataSource) { - parent = content; - } - return parent; + 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 @@ -240,13 +254,24 @@ public class ViewContextAction extends AbstractAction { } } } - + 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 { @@ -262,7 +287,7 @@ public class ViewContextAction extends AbstractAction { 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 dataSourceLevelNodes = Stream.of(rootChildren.getNodes()) .flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream()) .collect(Collectors.toList()); @@ -282,16 +307,22 @@ public class ViewContextAction extends AbstractAction { // 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 @@ -299,7 +330,7 @@ public class ViewContextAction extends AbstractAction { * 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) { @@ -312,7 +343,7 @@ public class ViewContextAction extends AbstractAction { 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)) { @@ -338,15 +369,16 @@ public class ViewContextAction extends AbstractAction { * returns itself. * * @param node The node. + * * @return The child nodes that are at the data source level. */ private List 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(); if (childNodes == null) { @@ -366,7 +398,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) { @@ -397,7 +430,7 @@ public class ViewContextAction extends AbstractAction { 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, From 976180eb11561edcf91cf6a12f5aaea20e1406e6 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Tue, 15 Jun 2021 18:52:45 -0400 Subject: [PATCH 14/18] load optimal --- .../autopsy/directorytree/ViewContextAction.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index 7dcbcf85de..f3f2dc0419 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -288,7 +288,7 @@ public class ViewContextAction extends AbstractAction { 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 dataSourceLevelNodes = Stream.of(rootChildren.getNodes()) + List dataSourceLevelNodes = Stream.of(rootChildren.getNodes(true)) .flatMap(rootNode -> getDataSourceLevelNodes(rootNode).stream()) .collect(Collectors.toList()); @@ -380,12 +380,12 @@ public class ViewContextAction extends AbstractAction { || 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 { @@ -441,8 +441,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(); From 61f6a436de5aae9baa14d3e223bd193917b5b41a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Jun 2021 10:09:05 -0400 Subject: [PATCH 15/18] 7639 add cancelation to ingest jobs panel --- .../autopsy/casemodule/IngestJobInfoPanel.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 6e1df2b8c0..d57df36767 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -59,6 +59,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private IngestModuleTableModel ingestModuleTableModel = new IngestModuleTableModel(null); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private DataSource selectedDataSource; + private static SwingWorker refreshWorker = null; /** * Creates new form IngestJobInfoPanel @@ -135,7 +136,10 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { * Get the updated complete list of ingest jobs. */ private void refresh() { - new SwingWorker() { + if (refreshWorker != null && !refreshWorker.isDone()){ + refreshWorker.cancel(true); + } + refreshWorker = new SwingWorker() { @Override protected Boolean doInBackground() throws Exception { @@ -165,7 +169,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { logger.log(Level.WARNING, "Error getting results from Ingest Job Info Panel's refresh worker", ex); } } - }.execute(); + }; + refreshWorker.execute(); } /** @@ -174,6 +179,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private void reset() { this.ingestJobs = new ArrayList<>(); setDataSource(null); + refreshWorker.cancel(true); } @Messages({"IngestJobInfoPanel.IngestJobTableModel.StartTime.header=Start Time", From 5f3a9ff04a0ee9f06940802c18e0ff8bcc2e1c17 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro Date: Wed, 16 Jun 2021 10:47:21 -0400 Subject: [PATCH 16/18] early return --- .../org/sleuthkit/autopsy/directorytree/ViewContextAction.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index f3f2dc0419..323b340c7f 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -174,6 +174,7 @@ public class ViewContextAction extends AbstractAction { 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. From e74def1be1b1f1eba6c02695d74f0ec74b217d6b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Jun 2021 10:53:50 -0400 Subject: [PATCH 17/18] 7639 - add null check --- .../sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index d57df36767..016027263a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -59,7 +59,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private IngestModuleTableModel ingestModuleTableModel = new IngestModuleTableModel(null); private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); private DataSource selectedDataSource; - private static SwingWorker refreshWorker = null; + private static SwingWorker refreshWorker = null; /** * Creates new form IngestJobInfoPanel @@ -136,7 +136,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { * Get the updated complete list of ingest jobs. */ private void refresh() { - if (refreshWorker != null && !refreshWorker.isDone()){ + if (refreshWorker != null && !refreshWorker.isDone()) { refreshWorker.cancel(true); } refreshWorker = new SwingWorker() { @@ -179,7 +179,9 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private void reset() { this.ingestJobs = new ArrayList<>(); setDataSource(null); - refreshWorker.cancel(true); + if (refreshWorker != null) { + refreshWorker.cancel(true); + } } @Messages({"IngestJobInfoPanel.IngestJobTableModel.StartTime.header=Start Time", From f122de443d98e832d775e748b146a8d3fbf90475 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 16 Jun 2021 11:19:50 -0400 Subject: [PATCH 18/18] 7639 re-order reset action to cancel before clearing --- .../sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java index 016027263a..5161a544ca 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/IngestJobInfoPanel.java @@ -53,7 +53,7 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED); private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE); private static final int EXTRA_ROW_HEIGHT = 4; - private List ingestJobs = new ArrayList<>(); + private final List ingestJobs = new ArrayList<>(); private final List ingestJobsForSelectedDataSource = new ArrayList<>(); private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel(); private IngestModuleTableModel ingestModuleTableModel = new IngestModuleTableModel(null); @@ -177,11 +177,11 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel { * Reset the panel. */ private void reset() { - this.ingestJobs = new ArrayList<>(); - setDataSource(null); if (refreshWorker != null) { refreshWorker.cancel(true); } + this.ingestJobs.clear(); + setDataSource(null); } @Messages({"IngestJobInfoPanel.IngestJobTableModel.StartTime.header=Start Time",