From 4efce24219e66a3dab71f9b2f0e65e83073d7d55 Mon Sep 17 00:00:00 2001 From: Greg DiCristofaro <gregd@basistech.com> Date: Wed, 20 Oct 2021 20:55:58 -0400 Subject: [PATCH] integrated updatable caches --- .../mainui/datamodel/AnalysisResultDAO.java | 6 +- .../datamodel/FileTypeSizeSearchParams.java | 25 +- .../mainui/datamodel/HashHitSearchParam.java | 5 + .../datamodel/KeywordHitSearchParam.java | 5 + .../autopsy/mainui/datamodel/ViewsDAO.java | 376 +++++++----------- .../mainui/nodes/SearchResultSupport.java | 6 +- .../mainui/datamodel/TableSearchTest.java | 58 +-- 7 files changed, 211 insertions(+), 270 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java index 90c3b69f1e..cddad9b779 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/AnalysisResultDAO.java @@ -183,15 +183,15 @@ protected void onModuleData(ModuleDataEvent evt) { caches.forEach((cache) -> cache.invalidate(evt)); } - public EventUpdatableCache<AnalysisResultSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getAnalysisResultsCache() { + public EventUpdatableCache<AnalysisResultSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getAnalysisResults() { return this.analysisResultCache; } - public EventUpdatableCache<HashHitSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getHashHitsCache() { + public EventUpdatableCache<HashHitSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getHashsetHits() { return this.hashHitCache; } - public EventUpdatableCache<KeywordHitSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getKeywordHitsCache() { + public EventUpdatableCache<KeywordHitSearchParam, AnalysisResultTableSearchResultsDTO, ModuleDataEvent> getKeywordHits() { return this.keywordHitCache; } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java index a07c789f92..1922c08ba2 100755 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/FileTypeSizeSearchParams.java @@ -25,18 +25,27 @@ */ public class FileTypeSizeSearchParams extends DataSourceFilteredSearchParams { + private static final long GB_1 = 1000 * 1000 * 1000; + private static final long MB_200 = 200 * 1000 * 1000; + private static final long MB_50 = 50 * 1000 * 1000; + public enum FileSizeFilter { - SIZE_50_200(0, "SIZE_50_200", "50 - 200MB"), //NON-NLS - SIZE_200_1000(1, "SIZE_200_1GB", "200MB - 1GB"), //NON-NLS - SIZE_1000_(2, "SIZE_1000+", "1GB+"); //NON-NLS + SIZE_50_200(0, "SIZE_50_200", "50 - 200MB", MB_50, MB_200), //NON-NLS + SIZE_200_1000(1, "SIZE_200_1GB", "200MB - 1GB", MB_200, GB_1), //NON-NLS + SIZE_1000_(2, "SIZE_1000+", "1GB+", GB_1, null); //NON-NLS private final int id; private final String name; private final String displayName; + private long lowerBound; + private Long upperBound; + - private FileSizeFilter(int id, String name, String displayName) { + private FileSizeFilter(int id, String name, String displayName, long lowerBound, Long upperBound) { this.id = id; this.name = name; this.displayName = displayName; + this.lowerBound = lowerBound; + this.upperBound = upperBound; } public String getName() { @@ -50,6 +59,14 @@ public int getId() { public String getDisplayName() { return this.displayName; } + + public long getLowerBound() { + return lowerBound; + } + + public Long getUpperBound() { + return upperBound; + } } private final FileSizeFilter sizeFilter; diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java index 9ef3f98af1..1775b7e361 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/HashHitSearchParam.java @@ -24,6 +24,11 @@ * Key for keyword hits in order to retrieve data from DAO. */ public class HashHitSearchParam extends AnalysisResultSetSearchParam { + + public HashHitSearchParam(Long dataSourceId, String setName) { + super(BlackboardArtifact.Type.TSK_HASHSET_HIT, dataSourceId, setName); + } + public HashHitSearchParam(Long dataSourceId, String setName, long startItem, Long maxResultsCount) { super(BlackboardArtifact.Type.TSK_HASHSET_HIT, dataSourceId, setName, startItem, maxResultsCount); } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java index 7a564a04b9..b9c2b43358 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/KeywordHitSearchParam.java @@ -24,6 +24,11 @@ * Key for keyword hits in order to retrieve data from DAO. */ public class KeywordHitSearchParam extends AnalysisResultSetSearchParam { + + public KeywordHitSearchParam(Long dataSourceId, String setName) { + super(BlackboardArtifact.Type.TSK_KEYWORD_HIT, dataSourceId, setName); + } + public KeywordHitSearchParam(String setName, Long dataSourceId, long startItem, Long maxResultsCount) { super(BlackboardArtifact.Type.TSK_KEYWORD_HIT, dataSourceId, setName, startItem, maxResultsCount); } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java index 2da9f69c65..32f6b75fc1 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/datamodel/ViewsDAO.java @@ -18,20 +18,14 @@ */ package org.sleuthkit.autopsy.mainui.datamodel; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; -import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -39,7 +33,6 @@ import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.datamodel.FileTypeExtensions; -import org.sleuthkit.autopsy.ingest.ModuleDataEvent; import org.sleuthkit.autopsy.mainui.datamodel.DataEventListener.DefaultDataEventListener; import org.sleuthkit.autopsy.mainui.datamodel.FileRowDTO.ExtensionMediaType; import org.sleuthkit.datamodel.AbstractFile; @@ -82,11 +75,6 @@ "ThreePanelViewsDAO.fileColumns.noDescription=No Description"}) public class ViewsDAO extends DefaultDataEventListener { - private static final int CACHE_SIZE = 15; // rule of thumb: 5 entries times number of cached SearchParams sub-types - private static final long CACHE_DURATION = 2; - private static final TimeUnit CACHE_DURATION_UNITS = TimeUnit.MINUTES; - private final Cache<DataSourceFilteredSearchParams, SearchResultsDTO> searchParamsCache = CacheBuilder.newBuilder().maximumSize(CACHE_SIZE).expireAfterAccess(CACHE_DURATION, CACHE_DURATION_UNITS).build(); - private static final String FILE_VIEW_EXT_TYPE_ID = "FILE_VIEW_BY_EXT"; private static final List<ColumnKey> FILE_COLUMNS = Arrays.asList( @@ -131,7 +119,7 @@ private static ColumnKey getFileColumnKey(String name) { return new ColumnKey(name, name, Bundle.ThreePanelViewsDAO_fileColumns_noDescription()); } - static ExtensionMediaType getExtensionMediaType(String ext) { + private static ExtensionMediaType getExtensionMediaType(String ext) { if (StringUtils.isBlank(ext)) { return ExtensionMediaType.UNCATEGORIZED; } else { @@ -160,158 +148,47 @@ static ExtensionMediaType getExtensionMediaType(String ext) { } } - private SleuthkitCase getCase() throws NoCurrentCaseException { - return Case.getCurrentCaseThrows().getSleuthkitCase(); - } + private final FilesByExtensionCache extensionCache = new FilesByExtensionCache(); + private final FilesByMimeCache mimeCache = new FilesByMimeCache(); + private final FilesBySizeCache sizeCache = new FilesBySizeCache(); + private final List<EventUpdatableCacheImpl<?, ?, Content>> caches = ImmutableList.of(extensionCache, mimeCache, sizeCache); - public SearchResultsDTO getFilesByExtension(FileTypeExtensionsSearchParams key) throws ExecutionException, IllegalArgumentException { - if (key.getFilter() == null) { - throw new IllegalArgumentException("Must have non-null filter"); - } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { - throw new IllegalArgumentException("Data source id must be greater than 0 or null"); - } - - return searchParamsCache.get(key, () -> fetchExtensionSearchResultsDTOs(key.getFilter(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); + public EventUpdatableCache<FileTypeExtensionsSearchParams, SearchResultsDTO, Content> getFileByExtensions() { + return this.extensionCache; } - public SearchResultsDTO getFilesByMime(FileTypeMimeSearchParams key) throws ExecutionException, IllegalArgumentException { - if (key.getMimeType() == null) { - throw new IllegalArgumentException("Must have non-null filter"); - } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { - throw new IllegalArgumentException("Data source id must be greater than 0 or null"); - } - - return searchParamsCache.get(key, () -> fetchMimeSearchResultsDTOs(key.getMimeType(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); - } - - public SearchResultsDTO getFilesBySize(FileTypeSizeSearchParams key) throws ExecutionException, IllegalArgumentException { - if (key.getSizeFilter() == null) { - throw new IllegalArgumentException("Must have non-null filter"); - } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { - throw new IllegalArgumentException("Data source id must be greater than 0 or null"); - } - - return searchParamsCache.get(key, () -> fetchSizeSearchResultsDTOs(key.getSizeFilter(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); - } - -// private ViewFileTableSearchResultsDTO fetchFilesForTable(ViewFileCacheKey cacheKey) throws NoCurrentCaseException, TskCoreException { -// -// } -// -// public ViewFileTableSearchResultsDTO getFilewViewForTable(BlackboardArtifact.Type artType, Long dataSourceId) throws ExecutionException, IllegalArgumentException { -// if (artType == null || artType.getCategory() != BlackboardArtifact.Category.DATA_ARTIFACT) { -// throw new IllegalArgumentException(MessageFormat.format("Illegal data. " -// + "Artifact type must be non-null and data artifact. " -// + "Received {0}", artType)); -// } -// -// ViewFileCacheKey cacheKey = new ViewFileCacheKey(artType, dataSourceId); -// return dataArtifactCache.get(cacheKey, () -> fetchFilesForTable(cacheKey)); -// } - private Map<Integer, Long> fetchFileViewCounts(List<FileExtSearchFilter> filters, Long dataSourceId) throws NoCurrentCaseException, TskCoreException { - Map<Integer, Long> counts = new HashMap<>(); - for (FileExtSearchFilter filter : filters) { - String whereClause = getFileExtensionWhereStatement(filter, dataSourceId); - long count = getCase().countFilesWhere(whereClause); - counts.put(filter.getId(), count); - } - - return counts; + public EventUpdatableCache<FileTypeMimeSearchParams, SearchResultsDTO, Content> getFileByMimeTypes() { + return mimeCache; } - private String getFileExtensionWhereStatement(FileExtSearchFilter filter, Long dataSourceId) { - String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" - + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "") - + (dataSourceId != null && dataSourceId > 0 - ? " AND data_source_obj_id = " + dataSourceId - : " ") - + " AND (extension IN (" + filter.getFilter().stream() - .map(String::toLowerCase) - .map(s -> "'" + StringUtils.substringAfter(s, ".") + "'") - .collect(Collectors.joining(", ")) + "))"; - return whereClause; + public EventUpdatableCache<FileTypeSizeSearchParams, SearchResultsDTO, Content> getFilesBySize() { + return sizeCache; } - private String getFileMimeWhereStatement(String mimeType, Long dataSourceId) { - - String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" - + " AND (type IN (" - + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," - + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," - + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," - + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + "," - + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() - + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) - + "))" - + (dataSourceId != null && dataSourceId > 0 ? " AND data_source_obj_id = " + dataSourceId : " ") - + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "") - + " AND mime_type = '" + mimeType + "'"; - - return whereClause; + private SleuthkitCase getCase() throws NoCurrentCaseException { + return Case.getCurrentCaseThrows().getSleuthkitCase(); } - private static String getFileSizesWhereStatement(FileTypeSizeSearchParams.FileSizeFilter filter, Long dataSourceId) { - String query; - switch (filter) { - case SIZE_50_200: - query = "(size >= 50000000 AND size < 200000000)"; //NON-NLS - break; - case SIZE_200_1000: - query = "(size >= 200000000 AND size < 1000000000)"; //NON-NLS - break; - - case SIZE_1000_: - query = "(size >= 1000000000)"; //NON-NLS - break; - - default: - throw new IllegalArgumentException("Unsupported filter type to get files by size: " + filter); //NON-NLS - } - - // Ignore unallocated block files. - query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS - - // hide known files if specified by configuration - query += (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); //NON-NLS - - // filter by datasource if indicated in case preferences - if (dataSourceId != null && dataSourceId > 0) { - query += " AND data_source_obj_id = " + dataSourceId; + private void validateDataSourceParams(DataSourceFilteredSearchParams searchParams) throws IllegalArgumentException { + if (searchParams == null) { + throw new IllegalArgumentException("Search parameters must be non-null"); + } else if (searchParams.getDataSourceId() != null && searchParams.getDataSourceId() <= 0) { + throw new IllegalArgumentException("Data source id must be greater than 0 or null"); } - - return query; - } - - private SearchResultsDTO fetchExtensionSearchResultsDTOs(FileExtSearchFilter filter, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { - String whereStatement = getFileExtensionWhereStatement(filter, dataSourceId); - return fetchFileViewFiles(whereStatement, filter.getDisplayName(), startItem, maxResultCount); - } - - @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"}) - private SearchResultsDTO fetchMimeSearchResultsDTOs(String mimeType, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { - String whereStatement = getFileMimeWhereStatement(mimeType, dataSourceId); - final String MIME_TYPE_DISPLAY_NAME = Bundle.FileTypesByMimeType_name_text(); - return fetchFileViewFiles(whereStatement, MIME_TYPE_DISPLAY_NAME, startItem, maxResultCount); - } - - private SearchResultsDTO fetchSizeSearchResultsDTOs(FileTypeSizeSearchParams.FileSizeFilter filter, Long dataSourceId, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { - String whereStatement = getFileSizesWhereStatement(filter, dataSourceId); - return fetchFileViewFiles(whereStatement, filter.getDisplayName(), startItem, maxResultCount); } private SearchResultsDTO fetchFileViewFiles(String whereStatement, String displayName, long startItem, Long maxResultCount) throws NoCurrentCaseException, TskCoreException { List<AbstractFile> files = getCase().findAllFilesWhere(whereStatement); - + Stream<AbstractFile> pagedFileStream = files.stream() .sorted(Comparator.comparing(af -> af.getId())) .skip(startItem); - + if (maxResultCount != null) { pagedFileStream = pagedFileStream.limit(maxResultCount); } - + List<AbstractFile> pagedFiles = pagedFileStream.collect(Collectors.toList()); - List<RowDTO> fileRows = new ArrayList<>(); for (AbstractFile file : pagedFiles) { @@ -371,106 +248,143 @@ private SearchResultsDTO fetchFileViewFiles(String whereStatement, String displa @Override public void dropCache() { - searchParamsCache.invalidateAll(); + caches.forEach((cache) -> cache.invalidateAll()); } @Override protected void onContentChange(Content content) { - if (!(content instanceof AbstractFile)) { - return; + caches.forEach((cache) -> cache.invalidate(content)); + } + + private class FilesByExtensionCache extends EventUpdatableCacheImpl<FileTypeExtensionsSearchParams, SearchResultsDTO, Content> { + + private String getFileExtensionWhereStatement(FileExtSearchFilter filter, Long dataSourceId) { + String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "") + + (dataSourceId != null && dataSourceId > 0 + ? " AND data_source_obj_id = " + dataSourceId + : " ") + + " AND (extension IN (" + filter.getFilter().stream() + .map(String::toLowerCase) + .map(s -> "'" + StringUtils.substringAfter(s, ".") + "'") + .collect(Collectors.joining(", ")) + "))"; + return whereClause; + } + + @Override + protected SearchResultsDTO fetch(FileTypeExtensionsSearchParams key) throws Exception { + String whereStatement = getFileExtensionWhereStatement(key.getFilter(), key.getDataSourceId()); + return fetchFileViewFiles(whereStatement, key.getFilter().getDisplayName(), key.getStartItem(), key.getMaxResultsCount()); + } + + @Override + public boolean isInvalidatingEvent(FileTypeExtensionsSearchParams key, Content eventData) { + if (!(eventData instanceof AbstractFile)) { + return false; + } + + AbstractFile file = (AbstractFile) eventData; + String extension = "." + file.getNameExtension().toLowerCase(); + return key.getFilter().getFilter().contains(extension); + } + + @Override + protected void validateCacheKey(FileTypeExtensionsSearchParams key) throws IllegalArgumentException { + validateDataSourceParams(key); + if (key.getFilter() == null) { + throw new IllegalArgumentException("Must have non-null filter"); + } + } + } + + private class FilesByMimeCache extends EventUpdatableCacheImpl<FileTypeMimeSearchParams, SearchResultsDTO, Content> { + + private String getFileMimeWhereStatement(String mimeType, Long dataSourceId) { + String whereClause = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + + " AND (type IN (" + + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," + + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," + + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," + + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + "," + + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() + + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + + "))" + + (dataSourceId != null && dataSourceId > 0 ? " AND data_source_obj_id = " + dataSourceId : " ") + + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "") + + " AND mime_type = '" + mimeType + "'"; + + return whereClause; + } + + @Override + @Messages({"FileTypesByMimeType.name.text=By MIME Type"}) + protected SearchResultsDTO fetch(FileTypeMimeSearchParams key) throws Exception { + String whereStatement = getFileMimeWhereStatement(key.getMimeType(), key.getDataSourceId()); + final String mimeTypeDisplayName = Bundle.FileTypesByMimeType_name_text(); + return fetchFileViewFiles(whereStatement, mimeTypeDisplayName, key.getStartItem(), key.getMaxResultsCount()); + } + + @Override + public boolean isInvalidatingEvent(FileTypeMimeSearchParams key, Content eventData) { + if (!(eventData instanceof AbstractFile)) { + return false; + } + + AbstractFile file = (AbstractFile) eventData; + String mimeType = file.getMIMEType(); + return key.getMimeType().equalsIgnoreCase(mimeType); } - AbstractFile file = (AbstractFile) content; - long dataSourceId = file.getDataSourceObjectId(); - // GVDTODO rewrite -// dropMimeTypeMatches(file.getMIMEType(), dataSourceId); -// dropFileExtMatches(file.getNameExtension(), dataSourceId); + @Override + protected void validateCacheKey(FileTypeMimeSearchParams key) throws IllegalArgumentException { + validateDataSourceParams(key); + if (key.getMimeType() == null) { + throw new IllegalArgumentException("Must have non-null filter"); + } + } } - - - - private abstract class ViewsDaoCache<K extends DataSourceFilteredSearchParams> extends EventUpdatableCacheImpl<K, SearchResultsDTO, ModuleContentEvent> { + + private class FilesBySizeCache extends EventUpdatableCacheImpl<FileTypeSizeSearchParams, SearchResultsDTO, Content> { + + private String getFileSizesWhereStatement(FileTypeSizeSearchParams.FileSizeFilter filter, Long dataSourceId) { + String lowerBound = "size >= " + filter.getLowerBound(); + String upperBound = filter.getUpperBound() == null ? "" : " AND size < " + filter.getUpperBound(); + String query = "(" + lowerBound + upperBound + ")"; + + // Ignore unallocated block files. + query += " AND (type != " + TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS.getFileType() + ")"; //NON-NLS + + // hide known files if specified by configuration + query += (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); //NON-NLS + + // filter by datasource if indicated in case preferences + if (dataSourceId != null && dataSourceId > 0) { + query += " AND data_source_obj_id = " + dataSourceId; + } + + return query; + } @Override - protected abstract SearchResultsDTO fetch(K key) throws Exception; + protected SearchResultsDTO fetch(FileTypeSizeSearchParams key) throws Exception { + String whereStatement = getFileSizesWhereStatement(key.getSizeFilter(), key.getDataSourceId()); + return fetchFileViewFiles(whereStatement, key.getSizeFilter().getDisplayName(), key.getStartItem(), key.getMaxResultsCount()); + } @Override - protected void validateCacheKey(K key) throws IllegalArgumentException { - super.validateCacheKey(key); //To change body of generated methods, choose Tools | Templates. + public boolean isInvalidatingEvent(FileTypeSizeSearchParams key, Content eventData) { + long size = eventData.getSize(); + + return size >= key.getSizeFilter().getLowerBound() + && (key.getSizeFilter().getUpperBound() == null || size < key.getSizeFilter().getUpperBound()); } @Override - public boolean isInvalidatingEvent(K key, ModuleDataEvent eventData) { - + protected void validateCacheKey(FileTypeSizeSearchParams key) throws IllegalArgumentException { + validateDataSourceParams(key); + if (key.getSizeFilter() == null) { + throw new IllegalArgumentException("Must have non-null filter"); + } } } - - - -// public SearchResultsDTO getFilesByExtension(FileTypeExtensionsSearchParams key) throws ExecutionException, IllegalArgumentException { -// if (key.getFilter() == null) { -// throw new IllegalArgumentException("Must have non-null filter"); -// } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { -// throw new IllegalArgumentException("Data source id must be greater than 0 or null"); -// } -// -// return searchParamsCache.get(key, () -> fetchExtensionSearchResultsDTOs(key.getFilter(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); -// } -// -// public SearchResultsDTO getFilesByMime(FileTypeMimeSearchParams key) throws ExecutionException, IllegalArgumentException { -// if (key.getMimeType() == null) { -// throw new IllegalArgumentException("Must have non-null filter"); -// } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { -// throw new IllegalArgumentException("Data source id must be greater than 0 or null"); -// } -// -// return searchParamsCache.get(key, () -> fetchMimeSearchResultsDTOs(key.getMimeType(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); -// } -// -// public SearchResultsDTO getFilesBySize(FileTypeSizeSearchParams key) throws ExecutionException, IllegalArgumentException { -// if (key.getSizeFilter() == null) { -// throw new IllegalArgumentException("Must have non-null filter"); -// } else if (key.getDataSourceId() != null && key.getDataSourceId() <= 0) { -// throw new IllegalArgumentException("Data source id must be greater than 0 or null"); -// } -// -// return searchParamsCache.get(key, () -> fetchSizeSearchResultsDTOs(key.getSizeFilter(), key.getDataSourceId(), key.getStartItem(), key.getMaxResultsCount())); -// } - -// private void dropFileExtMatches(String extension, long dataSourceId) { -// if (extension == null) { -// return; -// } -// -// String extKey = "." + extension; -// -// Set<FileExtSearchFilter> matchingFilters = Stream.of( -// FileExtDocumentFilter.values(), -// FileExtExecutableFilter.values(), -// FileExtRootFilter.values() -// ) -// .flatMap(arr -> Stream.of(arr)) -// .filter(filter -> filter.getFilter().contains(extKey)) -// .collect(Collectors.toSet()); -// -// this.searchParamsCache.asMap().replaceAll((k, v) -> { -// // if filter applies to this item -// return (matchingFilters.contains(k.getFilter()) -// // and data source ids are equal -// && (k.getDataSourceId() == null || k.getDataSourceId() == dataSourceId)) -// ? v -// : null; -// }); -// } -// -// private void dropMimeTypeMatches(String mimeType, long dataSourceId) { -// this.searchParamsCache.asMap().replaceAll((k, v) -> { -// // if mime types are equal -// return (((mimeType == null && k.getMimeType() == null) || (mimeType != null && mimeType.equals(k.getMimeType()))) -// // and data source ids are equal -// && (k.getDataSourceId() == null || k.getDataSourceId() == dataSourceId)) -// ? v -// : null; -// }); -// } } diff --git a/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultSupport.java b/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultSupport.java index 110deccf73..49e337722e 100644 --- a/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultSupport.java +++ b/Core/src/org/sleuthkit/autopsy/mainui/nodes/SearchResultSupport.java @@ -236,7 +236,7 @@ public synchronized SearchResultsDTO setFileExtensions(final FileTypeExtensionsS fileExtParameters.getDataSourceId(), pageIdx * pageSize, (long) pageSize); - return dao.getViewsDAO().getFilesByExtension(searchParams); + return dao.getViewsDAO().getFileByExtensions().getValue(searchParams); }; return fetchResults(); @@ -262,7 +262,7 @@ public synchronized SearchResultsDTO setDataArtifact(final DataArtifactSearchPar dataArtifactParameters.getDataSourceId(), pageIdx * pageSize, (long) pageSize); - return dao.getDataArtifactsDAO().getDataArtifactsForTable(searchParams); + return dao.getDataArtifactsDAO().getValue(searchParams); }; return fetchResults(); @@ -289,7 +289,7 @@ public synchronized SearchResultsDTO setFileMimes(FileTypeMimeSearchParams fileM fileMimeKey.getDataSourceId(), pageIdx * pageSize, (long) pageSize); - return dao.getViewsDAO().getFilesByMime(searchParams); + return dao.getViewsDAO().getFileByMimeTypes().getValue(searchParams); }; return fetchResults(); diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/mainui/datamodel/TableSearchTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/mainui/datamodel/TableSearchTest.java index d47b28273a..08807ad752 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/mainui/datamodel/TableSearchTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/mainui/datamodel/TableSearchTest.java @@ -320,28 +320,28 @@ public void dataArtifactSearchTest() { DataArtifactSearchParam param = new DataArtifactSearchParam(BlackboardArtifact.Type.TSK_CONTACT, null); DataArtifactDAO dataArtifactDAO = MainDAO.getInstance().getDataArtifactsDAO(); - DataArtifactTableSearchResultsDTO results = dataArtifactDAO.getDataArtifactsForTable(param); + DataArtifactTableSearchResultsDTO results = dataArtifactDAO.getValue(param); assertEquals(BlackboardArtifact.Type.TSK_CONTACT, results.getArtifactType()); assertEquals(2, results.getTotalResultsCount()); assertEquals(2, results.getItems().size()); // Get contacts from data source 2 param = new DataArtifactSearchParam(BlackboardArtifact.Type.TSK_CONTACT, dataSource2.getId()); - results = dataArtifactDAO.getDataArtifactsForTable(param); + results = dataArtifactDAO.getValue(param); assertEquals(BlackboardArtifact.Type.TSK_CONTACT, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get bookmarks from data source 2 param = new DataArtifactSearchParam(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, dataSource2.getId()); - results = dataArtifactDAO.getDataArtifactsForTable(param); + results = dataArtifactDAO.getValue(param); assertEquals(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, results.getArtifactType()); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Get all custom artifacts param = new DataArtifactSearchParam(customDataArtifactType, null); - results = dataArtifactDAO.getDataArtifactsForTable(param); + results = dataArtifactDAO.getValue(param); assertEquals(customDataArtifactType, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); @@ -387,37 +387,37 @@ public void mimeSearchTest() { // Get plain text files from data source 1 FileTypeMimeSearchParams param = new FileTypeMimeSearchParams("text/plain", dataSource1.getId()); - SearchResultsDTO results = viewsDAO.getFilesByMime(param); + SearchResultsDTO results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(2, results.getTotalResultsCount()); assertEquals(2, results.getItems().size()); // Get jpeg files from data source 1 param = new FileTypeMimeSearchParams("image/jpeg", dataSource1.getId()); - results = viewsDAO.getFilesByMime(param); + results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get jpeg files from data source 2 param = new FileTypeMimeSearchParams("image/jpeg", dataSource2.getId()); - results = viewsDAO.getFilesByMime(param); + results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Search for mime type that should produce no results param = new FileTypeMimeSearchParams("blah/blah", null); - results = viewsDAO.getFilesByMime(param); + results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Get plain text files from all data sources param = new FileTypeMimeSearchParams("text/plain", null); - results = viewsDAO.getFilesByMime(param); + results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(3, results.getTotalResultsCount()); assertEquals(3, results.getItems().size()); // Get the custom file by MIME type param = new FileTypeMimeSearchParams(CUSTOM_MIME_TYPE, null); - results = viewsDAO.getFilesByMime(param); + results = viewsDAO.getFileByMimeTypes().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); @@ -442,31 +442,31 @@ public void sizeSearchTest() { // Get "50 - 200MB" files from data source 1 FileTypeSizeSearchParams param = new FileTypeSizeSearchParams(FileTypeSizeSearchParams.FileSizeFilter.SIZE_50_200, dataSource1.getId()); - SearchResultsDTO results = viewsDAO.getFilesBySize(param); + SearchResultsDTO results = viewsDAO.getFilesBySize().getValue(param); assertEquals(2, results.getTotalResultsCount()); assertEquals(2, results.getItems().size()); // Get "200MB - 1GB" files from data source 1 param = new FileTypeSizeSearchParams(FileTypeSizeSearchParams.FileSizeFilter.SIZE_200_1000, dataSource1.getId()); - results = viewsDAO.getFilesBySize(param); + results = viewsDAO.getFilesBySize().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Get "200MB - 1GB" files from data source 2 param = new FileTypeSizeSearchParams(FileTypeSizeSearchParams.FileSizeFilter.SIZE_200_1000, dataSource2.getId()); - results = viewsDAO.getFilesBySize(param); + results = viewsDAO.getFilesBySize().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get "1GB+" files from all data sources param = new FileTypeSizeSearchParams(FileTypeSizeSearchParams.FileSizeFilter.SIZE_1000_, null); - results = viewsDAO.getFilesBySize(param); + results = viewsDAO.getFilesBySize().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Get "50 - 200MB" files from all data sources param = new FileTypeSizeSearchParams(FileTypeSizeSearchParams.FileSizeFilter.SIZE_50_200, null); - results = viewsDAO.getFilesBySize(param); + results = viewsDAO.getFilesBySize().getValue(param); assertEquals(3, results.getTotalResultsCount()); assertEquals(3, results.getItems().size()); } catch (ExecutionException ex) { @@ -484,21 +484,21 @@ public void analysisResultSearchTest() { AnalysisResultSearchParam param = new AnalysisResultSearchParam(BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, null); AnalysisResultDAO analysisResultDAO = MainDAO.getInstance().getAnalysisResultDAO(); - AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getAnalysisResultsForTable(param); + AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getAnalysisResults().getValue(param); assertEquals(BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, results.getArtifactType()); assertEquals(3, results.getTotalResultsCount()); assertEquals(3, results.getItems().size()); // Get encryption detected artifacts from data source 2 param = new AnalysisResultSearchParam(BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, dataSource2.getId()); - results = analysisResultDAO.getAnalysisResultsForTable(param); + results = analysisResultDAO.getAnalysisResults().getValue(param); assertEquals(BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get all custom artifacts param = new AnalysisResultSearchParam(customAnalysisResultType, null); - results = analysisResultDAO.getAnalysisResultsForTable(param); + results = analysisResultDAO.getAnalysisResults().getValue(param); assertEquals(customAnalysisResultType, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); @@ -538,13 +538,13 @@ private void hashHitSearchTest() { // Test hash set hits AnalysisResultDAO analysisResultDAO = MainDAO.getInstance().getAnalysisResultDAO(); HashHitSearchParam hashParam = new HashHitSearchParam(null, HASH_SET_1); - AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getHashHitsForTable(hashParam); + AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getHashsetHits().getValue(hashParam); assertEquals(BlackboardArtifact.Type.TSK_HASHSET_HIT, results.getArtifactType()); assertEquals(3, results.getTotalResultsCount()); assertEquals(3, results.getItems().size()); hashParam = new HashHitSearchParam(dataSource2.getId(), HASH_SET_1); - results = analysisResultDAO.getHashHitsForTable(hashParam); + results = analysisResultDAO.getHashsetHits().getValue(hashParam); assertEquals(BlackboardArtifact.Type.TSK_HASHSET_HIT, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); @@ -577,13 +577,13 @@ private void keywordHitSearchTest() { // Test keyword set hits AnalysisResultDAO analysisResultDAO = MainDAO.getInstance().getAnalysisResultDAO(); KeywordHitSearchParam kwParam = new KeywordHitSearchParam(null, KEYWORD_SET_1); - AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getKeywordHitsForTable(kwParam); + AnalysisResultTableSearchResultsDTO results = analysisResultDAO.getKeywordHits().getValue(kwParam); assertEquals(BlackboardArtifact.Type.TSK_KEYWORD_HIT, results.getArtifactType()); assertEquals(2, results.getTotalResultsCount()); assertEquals(2, results.getItems().size()); kwParam = new KeywordHitSearchParam(dataSource2.getId(), KEYWORD_SET_1); - results = analysisResultDAO.getKeywordHitsForTable(kwParam); + results = analysisResultDAO.getKeywordHits().getValue(kwParam); assertEquals(BlackboardArtifact.Type.TSK_KEYWORD_HIT, results.getArtifactType()); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); @@ -621,43 +621,43 @@ public void extensionSearchTest() { // Get all text documents from data source 1 FileTypeExtensionsSearchParams param = new FileTypeExtensionsSearchParams(FileExtRootFilter.TSK_DOCUMENT_FILTER, dataSource1.getId()); - SearchResultsDTO results = viewsDAO.getFilesByExtension(param); + SearchResultsDTO results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(3, results.getTotalResultsCount()); assertEquals(3, results.getItems().size()); // Get Word documents from data source 1 param = new FileTypeExtensionsSearchParams(FileExtDocumentFilter.AUT_DOC_OFFICE, dataSource1.getId()); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get image/jpeg files from data source 1 param = new FileTypeExtensionsSearchParams(FileExtRootFilter.TSK_IMAGE_FILTER, dataSource1.getId()); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); // Get text documents from all data sources param = new FileTypeExtensionsSearchParams(FileExtRootFilter.TSK_DOCUMENT_FILTER, null); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(4, results.getTotalResultsCount()); assertEquals(4, results.getItems().size()); // Get jpeg files from data source 2 param = new FileTypeExtensionsSearchParams(FileExtRootFilter.TSK_IMAGE_FILTER, dataSource2.getId()); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Search for file extensions that should produce no results param = new FileTypeExtensionsSearchParams(CustomRootFilter.EMPTY_RESULT_SET_FILTER, null); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(0, results.getTotalResultsCount()); assertEquals(0, results.getItems().size()); // Get the custom file by extension param = new FileTypeExtensionsSearchParams(CustomRootFilter.CUSTOM_FILTER, null); - results = viewsDAO.getFilesByExtension(param); + results = viewsDAO.getFileByExtensions().getValue(param); assertEquals(1, results.getTotalResultsCount()); assertEquals(1, results.getItems().size()); -- GitLab