factory fixes

This commit is contained in:
Greg DiCristofaro 2022-01-19 09:36:32 -05:00
parent d6a239f7bd
commit 2e9082bf65
3 changed files with 80 additions and 142 deletions

View File

@ -232,24 +232,34 @@ public class EmailsDAO extends AbstractDAO {
return safePath; return safePath;
} }
public static class EmailTreeItem extends TreeItemDTO<EmailSearchParams> { public TreeItemDTO<EmailSearchParams> createEmailTreeItem(String fullFolder, Long dataSourceId, TreeDisplayCount count) {
return new TreeItemDTO<>(
private final Optional<Boolean> hasChildren;
EmailTreeItem(String fullFolder, Long dataSourceId, TreeDisplayCount count,
Boolean hasChildren) {
super(
EmailSearchParams.getTypeId(), EmailSearchParams.getTypeId(),
new EmailSearchParams(dataSourceId, fullFolder), new EmailSearchParams(dataSourceId, fullFolder),
fullFolder == null ? 0 : fullFolder, fullFolder == null ? 0 : fullFolder,
getFolderDisplayName(fullFolder), getFolderDisplayName(fullFolder),
count count
); );
this.hasChildren = Optional.ofNullable(hasChildren);
} }
public Optional<Boolean> getHasChildren() {
return hasChildren; public Optional<String> getNextSubFolder(String folderParent, String folder) {
String normalizedParent = folderParent == null ? null : getNormalizedPath(folderParent);
String normalizedFolder = folder == null ? null : getNormalizedPath(folder);
if (normalizedParent == null || normalizedFolder.startsWith(normalizedParent)) {
if (normalizedFolder == null) {
return Optional.of(null);
} else {
int nextDelim = normalizedFolder.indexOf(PATH_DELIMITER, normalizedParent.length());
if (nextDelim >= 0) {
return Optional.of(normalizedFolder.substring(normalizedParent.length(), nextDelim));
} else {
return Optional.of(normalizedFolder.substring(normalizedParent.length()));
}
}
} else {
return Optional.empty();
} }
} }
@ -383,8 +393,7 @@ public class EmailsDAO extends AbstractDAO {
? TreeDisplayCount.INDETERMINATE ? TreeDisplayCount.INDETERMINATE
: TreeResultsDTO.TreeDisplayCount.getDeterminate(resultSet.getLong("count")); : TreeResultsDTO.TreeDisplayCount.getDeterminate(resultSet.getLong("count"));
accumulatedData.add( accumulatedData.add(createEmailTreeItem(getNormalizedPath(rsPath), dataSourceId, treeDisplayCount));
new EmailTreeItem(getNormalizedPath(rsPath), dataSourceId, treeDisplayCount, hasChildren));
} }
} catch (SQLException ex) { } catch (SQLException ex) {
throw new IllegalStateException("A sql exception occurred.", ex); throw new IllegalStateException("A sql exception occurred.", ex);
@ -414,11 +423,10 @@ public class EmailsDAO extends AbstractDAO {
Set<? extends DAOEvent> handleIngestComplete() { Set<? extends DAOEvent> handleIngestComplete() {
return SubDAOUtils.getIngestCompleteEvents( return SubDAOUtils.getIngestCompleteEvents(
this.emailCounts, this.emailCounts,
(daoEvt, count) -> new EmailTreeItem( (daoEvt, count) -> createEmailTreeItem(
getNormalizedPath(daoEvt.getFolder()), getNormalizedPath(daoEvt.getFolder()),
daoEvt.getDataSourceId(), daoEvt.getDataSourceId(),
count, count
daoEvt.getHasChildren().orElse(null)
)); ));
} }
@ -426,11 +434,10 @@ public class EmailsDAO extends AbstractDAO {
Set<TreeEvent> shouldRefreshTree() { Set<TreeEvent> shouldRefreshTree() {
return SubDAOUtils.getRefreshEvents( return SubDAOUtils.getRefreshEvents(
this.emailCounts, this.emailCounts,
(daoEvt, count) -> new EmailTreeItem( (daoEvt, count) -> createEmailTreeItem(
getNormalizedPath(daoEvt.getFolder()), getNormalizedPath(daoEvt.getFolder()),
daoEvt.getDataSourceId(), daoEvt.getDataSourceId(),
count, count
daoEvt.getHasChildren().orElse(null)
)); ));
} }
@ -469,18 +476,17 @@ public class EmailsDAO extends AbstractDAO {
for (Entry<String, Set<Long>> folderEntry : emailMap.entrySet()) { for (Entry<String, Set<Long>> folderEntry : emailMap.entrySet()) {
String folder = folderEntry.getKey(); String folder = folderEntry.getKey();
for (Long dsObjId : folderEntry.getValue()) { for (Long dsObjId : folderEntry.getValue()) {
emailEvents.add(new EmailEvent(dsObjId, folder, null)); emailEvents.add(new EmailEvent(dsObjId, folder));
} }
} }
Stream<TreeEvent> treeEvents = this.emailCounts.enqueueAll(emailEvents).stream() Stream<TreeEvent> treeEvents = this.emailCounts.enqueueAll(emailEvents).stream()
.map(daoEvt -> { .map(daoEvt -> {
return new TreeEvent( return new TreeEvent(
new EmailTreeItem( createEmailTreeItem(
daoEvt.getFolder(), daoEvt.getFolder(),
daoEvt.getDataSourceId(), daoEvt.getDataSourceId(),
TreeResultsDTO.TreeDisplayCount.INDETERMINATE, TreeResultsDTO.TreeDisplayCount.INDETERMINATE),
null),
false); false);
}); });
@ -509,6 +515,7 @@ public class EmailsDAO extends AbstractDAO {
} }
} }
/** /**
* Handles fetching and paging of data for communication accounts. * Handles fetching and paging of data for communication accounts.
*/ */

View File

@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.mainui.datamodel.events; package org.sleuthkit.autopsy.mainui.datamodel.events;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
/** /**
@ -28,7 +27,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
public class EmailEvent extends DataArtifactEvent { public class EmailEvent extends DataArtifactEvent {
private final String folder; private final String folder;
private final Optional<Boolean> hasChildren;
/** /**
* Main constructor. * Main constructor.
@ -36,22 +34,16 @@ public class EmailEvent extends DataArtifactEvent {
* @param dataSourceId The data source id that the email message belongs to. * @param dataSourceId The data source id that the email message belongs to.
* @param account The email message account. * @param account The email message account.
* @param folder The folder within that account of the email message. * @param folder The folder within that account of the email message.
* @param hasChildren True if this folder has further tree folders. Null if unknown.
*/ */
public EmailEvent(long dataSourceId, String folder, Boolean hasChildren) { public EmailEvent(long dataSourceId, String folder) {
super(BlackboardArtifact.Type.TSK_EMAIL_MSG, dataSourceId); super(BlackboardArtifact.Type.TSK_EMAIL_MSG, dataSourceId);
this.folder = folder; this.folder = folder;
this.hasChildren = Optional.ofNullable(hasChildren);
} }
public String getFolder() { public String getFolder() {
return folder; return folder;
} }
public Optional<Boolean> getHasChildren() {
return hasChildren;
}
@Override @Override
public int hashCode() { public int hashCode() {
int hash = 7; int hash = 7;

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.mainui.nodes; package org.sleuthkit.autopsy.mainui.nodes;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.Children; import org.openide.nodes.Children;
@ -135,7 +136,7 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
super(itemData.getSearchParams().getArtifactType().getTypeName(), super(itemData.getSearchParams().getArtifactType().getTypeName(),
getIconPath(itemData.getSearchParams().getArtifactType()), getIconPath(itemData.getSearchParams().getArtifactType()),
itemData, itemData,
Children.create(new EmailAccountTypeFactory(itemData.getSearchParams().getDataSourceId()), true), Children.create(new EmailFolderFactory(null, itemData.getSearchParams().getDataSourceId()), true),
getDefaultLookup(itemData) getDefaultLookup(itemData)
); );
} }
@ -268,19 +269,22 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
/** /**
* Factory for displaying account types. * Factory for displaying account types.
*/ */
static class EmailAccountTypeFactory extends TreeChildFactory<EmailSearchParams> { static class EmailFolderFactory extends TreeChildFactory<EmailSearchParams> {
private final String folderParent;
private final Long dataSourceId; private final Long dataSourceId;
/** /**
* Main constructor. * Main constructor.
* *
* @param folderParent The email parent folder for the factory.
* @param dataSourceId The data source object id for which the results * @param dataSourceId The data source object id for which the results
* should be filtered or null if no data source * should be filtered or null if no data source
* filtering. * filtering.
*/ */
public EmailAccountTypeFactory(Long dataSourceId) { public EmailFolderFactory(String folderParent, Long dataSourceId) {
this.dataSourceId = dataSourceId; this.dataSourceId = dataSourceId;
this.folderParent = folderParent;
} }
private EmailsDAO getDAO() { private EmailsDAO getDAO() {
@ -289,12 +293,12 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
@Override @Override
protected TreeResultsDTO<? extends EmailSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException { protected TreeResultsDTO<? extends EmailSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return getDAO().getEmailCounts(dataSourceId, null); return getDAO().getEmailCounts(dataSourceId, this.folderParent);
} }
@Override @Override
protected TreeNode<EmailSearchParams> createNewNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> rowData) { protected TreeNode<EmailSearchParams> createNewNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> rowData) {
return new EmailAccountTypeNode(rowData); return new EmailNode(rowData);
} }
@Override @Override
@ -303,103 +307,20 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
TreeItemDTO<EmailSearchParams> originalTreeItem = getTypedTreeItem(treeEvt, EmailSearchParams.class); TreeItemDTO<EmailSearchParams> originalTreeItem = getTypedTreeItem(treeEvt, EmailSearchParams.class);
if (originalTreeItem != null if (originalTreeItem != null
// ensure data source id for factory is null or data sources are equal
&& (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) { && (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {
EmailSearchParams originalSearchParam = originalTreeItem.getSearchParams(); EmailSearchParams originalSearchParam = originalTreeItem.getSearchParams();
Optional<String> thisSubFolderOpt = getDAO().getNextSubFolder(this.folderParent, originalSearchParam.getFolder());
if (thisSubFolderOpt.isPresent()) {
String thisSubFolder = thisSubFolderOpt.get();
return getDAO().createEmailTreeItem( return getDAO().createEmailTreeItem(
originalSearchParam.getAccount(), thisSubFolder,
null,
getDAO().getAccountDisplayName(originalSearchParam.getAccount(), null),
dataSourceId, dataSourceId,
originalTreeItem.getDisplayCount()); originalTreeItem.getDisplayCount());
} }
return null;
}
@Override
public int compare(TreeItemDTO<? extends EmailSearchParams> o1, TreeItemDTO<? extends EmailSearchParams> o2) {
boolean firstDown = o1.getSearchParams().getAccount() == null;
boolean secondDown = o2.getSearchParams().getAccount() == null;
if (firstDown == secondDown) {
return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName());
} else {
return Boolean.compare(firstDown, secondDown);
}
}
}
/**
* A node representing a single account type in the tree.
*/
static class EmailAccountTypeNode extends TreeNode<EmailSearchParams> {
/**
* Main constructor.
*
* @param itemData The data to display.
*/
public EmailAccountTypeNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> itemData) {
super(itemData.getSearchParams().getAccount(),
"org/sleuthkit/autopsy/images/account-icon-16.png",
itemData,
Children.create(new EmailFolderTypeFactory(itemData.getSearchParams().getAccount(), itemData.getSearchParams().getDataSourceId()), true),
getDefaultLookup(itemData)
);
}
}
/**
* Factory for displaying account types.
*/
static class EmailFolderTypeFactory extends TreeChildFactory<EmailSearchParams> {
private final String account;
private final Long dataSourceId;
/**
* Main constructor.
*
* @param account The email account for the factory.
* @param dataSourceId The data source object id for which the results
* should be filtered or null if no data source
* filtering.
*/
public EmailFolderTypeFactory(String account, Long dataSourceId) {
this.dataSourceId = dataSourceId;
this.account = account;
}
private EmailsDAO getDAO() {
return MainDAO.getInstance().getEmailsDAO();
}
@Override
protected TreeResultsDTO<? extends EmailSearchParams> getChildResults() throws IllegalArgumentException, ExecutionException {
return getDAO().getEmailCounts(dataSourceId, account);
}
@Override
protected TreeNode<EmailSearchParams> createNewNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> rowData) {
return new EmailFolderTypeNode(rowData);
}
@Override
protected TreeItemDTO<? extends EmailSearchParams> getOrCreateRelevantChild(TreeEvent treeEvt) {
TreeItemDTO<EmailSearchParams> originalTreeItem = getTypedTreeItem(treeEvt, EmailSearchParams.class);
if (originalTreeItem != null
&& Objects.equals(this.account, originalTreeItem.getSearchParams().getAccount())
&& (this.dataSourceId == null || Objects.equals(this.dataSourceId, originalTreeItem.getSearchParams().getDataSourceId()))) {
EmailSearchParams originalSearchParam = originalTreeItem.getSearchParams();
return getDAO().createEmailTreeItem(
originalSearchParam.getAccount(),
originalSearchParam.getFolder(),
getDAO().getFolderDisplayName(originalSearchParam.getFolder()),
dataSourceId,
originalTreeItem.getDisplayCount());
} }
return null; return null;
@ -421,24 +342,42 @@ public class DataArtifactTypeFactory extends TreeChildFactory<DataArtifactSearch
/** /**
* A node representing a single account type in the tree. * A node representing a single account type in the tree.
*/ */
static class EmailFolderTypeNode extends TreeNode<EmailSearchParams> { static class EmailNode extends TreeNode<EmailSearchParams> {
private final Children children;
/** /**
* Main constructor. * Main constructor.
* *
* @param itemData The data to display. * @param itemData The data to display.
*/ */
public EmailFolderTypeNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> itemData) { public EmailNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> itemData) {
this(itemData, Children.create(new EmailFolderFactory(itemData.getSearchParams().getFolder(), itemData.getSearchParams().getDataSourceId()), true));
}
private EmailNode(TreeResultsDTO.TreeItemDTO<? extends EmailSearchParams> itemData, Children children) {
super(itemData.getSearchParams().getFolder(), super(itemData.getSearchParams().getFolder(),
"org/sleuthkit/autopsy/images/folder-icon-16.png", "org/sleuthkit/autopsy/images/folder-icon-16.png",
itemData); itemData,
children,
getDefaultLookup(itemData));
this.children = children;
}
private boolean hasChildren() {
return this.children.getNodesCount(true) > 0;
} }
@Override @Override
public void respondSelection(DataResultTopComponent dataResultPanel) { public void respondSelection(DataResultTopComponent dataResultPanel) {
if (hasChildren()) {
super.respondSelection(dataResultPanel);
} else {
dataResultPanel.displayEmailMessages(super.getItemData().getSearchParams()); dataResultPanel.displayEmailMessages(super.getItemData().getSearchParams());
} }
} }
}
/** /**
* The root credit card node. * The root credit card node.