Merge branch 'develop' of github.com:sleuthkit/autopsy into 7276_hostPersonEvents

This commit is contained in:
Greg DiCristofaro 2021-03-02 15:00:06 -05:00
commit 87b92d9066
7 changed files with 118 additions and 54 deletions

View File

@ -57,6 +57,7 @@ FileSorter.SortingMethod.fullPath.displayName=Full Path
FileSorter.SortingMethod.keywordlist.displayName=Keyword List Names
FileSorter.SortingMethod.pageViews.displayName=Page Views
ResultDomain_getDefaultCategory=Uncategorized
ResultDomain_noAccountTypes=Unknown
ResultFile.score.interestingResult.description=At least one instance of the file has an interesting result associated with it.
ResultFile.score.notableFile.description=At least one instance of the file was recognized as notable.
ResultFile.score.notableTaggedFile.description=At least one instance of the file is tagged with a notable tag.

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -44,11 +44,13 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_D
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_ACCOUNT_TYPE;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
import org.sleuthkit.datamodel.CaseDbAccessManager;
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Loads domain search results for cache misses. This loader is a Guava cache
@ -103,11 +105,9 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
// Filters chosen in the UI are aggregated into SQL statements to be used in
// the queries that follow.
final Pair<String, String> filterClauses = createWhereAndHavingClause(key.getFilters());
final String whereClause = filterClauses.getLeft();
final String havingClause = filterClauses.getRight();
// You may think of each row of this result as a TSK_DOMAIN attribute, where the parent
final Pair<String, String> domainsFilterClauses = createWhereAndHavingClause(key.getFilters());
final String domainsWhereClause = domainsFilterClauses.getLeft();
final String domainsHavingClause = domainsFilterClauses.getRight();
// artifact type is within the (optional) filter and the parent artifact
// had a date time attribute that was within the (optional) filter. With this
// table in hand, we can simply group by domain and apply aggregate functions
@ -118,10 +118,31 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
+ " artifact_id AS parent_artifact_id,"
+ " MAX(artifact_type_id) AS parent_artifact_type_id "
+ "FROM blackboard_attributes "
+ "WHERE " + whereClause + " "
+ "WHERE " + domainsWhereClause + " "
+ "GROUP BY artifact_id "
+ "HAVING " + havingClause;
+ "HAVING " + domainsHavingClause;
final SleuthkitCase caseDb = key.getSleuthkitCase();
String sqlSpecificAccountAggregator;
if (caseDb.getDatabaseType() == TskData.DbType.POSTGRESQL) {
sqlSpecificAccountAggregator = "STRING_AGG(DISTINCT(value_text), ',')"; //postgres string aggregator (requires specified separator
} else {
sqlSpecificAccountAggregator = "GROUP_CONCAT(DISTINCT(value_text))"; //sqlite string aggregator (uses comma separation by default)
}
/*
* As part of getting the known account types for a domain additional
* attribute values are necessary from the blackboard_attributes table
* This sub-query aggregates them and associates them with the artifact
* they correspond to.
*/
final String accountsTable
= "SELECT " + sqlSpecificAccountAggregator + " as value_text," //naming field value_text the same as the field it is aggregating to re-use aggregator
+ "artifact_id AS account_artifact_id "
+ "FROM blackboard_attributes "
+ "WHERE (attribute_type_id = " + TSK_TEXT.getTypeID()
+ " AND value_text <> '' "
+ " AND (artifact_type_id = " + TSK_WEB_ACCOUNT_TYPE.getTypeID() + ")) "
+ "GROUP BY artifact_id ";
// Needed to populate the visitsInLast60 data.
final Instant mostRecentActivityDate = Instant.ofEpochSecond(caseDb.getTimelineManager().getMaxEventTime());
final Instant sixtyDaysAgo = mostRecentActivityDate.minus(60, ChronoUnit.DAYS);
@ -166,16 +187,18 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
+ " WHEN artifact_type_id = " + TSK_WEB_ACCOUNT_TYPE.getTypeID() + " THEN 1 "
+ " ELSE 0 "
+ " END) AS countOfKnownAccountTypes,"
+ " MAX(data_source_obj_id) AS dataSource "
+ "FROM blackboard_artifacts"
+ " MAX(data_source_obj_id) AS dataSource, "
+ sqlSpecificAccountAggregator + " as accountTypes "
+ "FROM blackboard_artifacts as barts"
+ " JOIN (" + domainsTable + ") AS domains_table"
+ " ON artifact_id = parent_artifact_id "
+ " ON barts.artifact_id = parent_artifact_id "
+ " LEFT JOIN (" + accountsTable + ") AS accounts_table"
+ " ON barts.artifact_id = account_artifact_id "
+ // Add the data source where clause here if present.
((dataSourceWhereClause != null) ? "WHERE " + dataSourceWhereClause + " " : "")
+ "GROUP BY " + groupByClause;
final CaseDbAccessManager dbManager = caseDb.getCaseDbAccessManager();
final DomainCallback domainCallback = new DomainCallback(caseDb);
dbManager.select(domainsQuery, domainCallback);
@ -208,8 +231,8 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
* to stress that these clauses are tightly coupled.
*/
Pair<String, String> createWhereAndHavingClause(List<AbstractFilter> filters) {
final StringJoiner whereClause = new StringJoiner(" OR ");
final StringJoiner havingClause = new StringJoiner(" AND ");
final StringJoiner whereClause = new StringJoiner(" OR ", "(", ")");
final StringJoiner havingClause = new StringJoiner(" AND ", "(", ")");
// Capture all types by default.
ArtifactTypeFilter artifactTypeFilter = new ArtifactTypeFilter(SearchData.Type.DOMAIN.getArtifactTypes());
@ -219,7 +242,7 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
if (filter instanceof ArtifactTypeFilter) {
// Replace with user defined types.
artifactTypeFilter = ((ArtifactTypeFilter) filter);
} else if (!(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) {
} else if (filter != null && !(filter instanceof DataSourceFilter) && !filter.useAlternateFilter()) {
if (filter instanceof ArtifactDateRangeFilter) {
hasDateTimeFilter = true;
}
@ -300,11 +323,12 @@ class DomainSearchCacheLoader extends CacheLoader<SearchKey, Map<GroupKey, List<
long pageViewsInLast60 = resultSet.getLong("pageViewsInLast60");
long countOfKnownAccountTypes = resultSet.getLong("countOfKnownAccountTypes");
long dataSourceID = resultSet.getLong("dataSource");
String accountTypes = resultSet.getString("accountTypes");
Content dataSource = skc.getContentById(dataSourceID);
resultDomains.add(new ResultDomain(domain, activityStart,
activityEnd, totalPageViews, pageViewsInLast60, filesDownloaded,
countOfKnownAccountTypes, dataSource));
countOfKnownAccountTypes, accountTypes, dataSource));
}
} catch (SQLException ex) {
this.sqlCause = ex;

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.discovery.search;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskData;
@ -34,6 +35,7 @@ public class ResultDomain extends Result {
private final Long pageViewsInLast60;
private final Long filesDownloaded;
private final Long countOfKnownAccountTypes;
private final String accountTypes;
private String webCategory;
private final Content dataSource;
@ -45,7 +47,7 @@ public class ResultDomain extends Result {
* @param domain The domain the result is being created from.
*/
ResultDomain(String domain, Long activityStart, Long activityEnd, Long totalPageViews,
Long pageViewsInLast60, Long filesDownloaded, Long countOfKnownAccountTypes, Content dataSource) {
Long pageViewsInLast60, Long filesDownloaded, Long countOfKnownAccountTypes, String accountTypes, Content dataSource) {
this.domain = domain;
this.dataSource = dataSource;
this.dataSourceId = dataSource.getId();
@ -55,6 +57,7 @@ public class ResultDomain extends Result {
this.pageViewsInLast60 = pageViewsInLast60;
this.filesDownloaded = filesDownloaded;
this.countOfKnownAccountTypes = countOfKnownAccountTypes;
this.accountTypes = accountTypes;
}
/**
@ -85,8 +88,8 @@ public class ResultDomain extends Result {
}
/**
* Get the total number of page views that this domain has had.
* Pages views is defined as the count of TSK_WEB_HISTORY artifacts.
* Get the total number of page views that this domain has had. Pages views
* is defined as the count of TSK_WEB_HISTORY artifacts.
*
* @return The total number of page views that this domain has had.
*/
@ -95,8 +98,8 @@ public class ResultDomain extends Result {
}
/**
* Get the number of page views that this domain has had in the last 60 days.
* Page views is defined as the count of TSK_WEB_HISTORY artifacts.
* Get the number of page views that this domain has had in the last 60
* days. Page views is defined as the count of TSK_WEB_HISTORY artifacts.
*
* @return The number of page views that this domain has had in the last 60
* days.
@ -113,7 +116,7 @@ public class ResultDomain extends Result {
public Long getFilesDownloaded() {
return filesDownloaded;
}
/**
* Get the web category (TSK_WEB_CATEGORY) type for this domain.
*/
@ -127,23 +130,41 @@ public class ResultDomain extends Result {
return webCategory;
}
}
/**
* Set the web category for this domain (derived from TSK_WEB_CATEGORY) artifacts.
* Set the web category for this domain (derived from TSK_WEB_CATEGORY)
* artifacts.
*/
public void setWebCategory(String webCategory) {
this.webCategory = webCategory;
}
/**
* Determines if the domain has been associated with a known account type
* (TSK_WEB_ACCOUNT_TYPE).
*/
public boolean hasKnownAccountType() {
return countOfKnownAccountTypes != null
return countOfKnownAccountTypes != null
&& countOfKnownAccountTypes > 0;
}
/**
* Get the account types which are associated with this domain.
*
* @return A comma seperated list of account types which are associated with
* this domain, or "Unknown" if no account types were associated
* with it.
*/
@NbBundle.Messages({
"ResultDomain_noAccountTypes=Unknown"
})
public String getAccountTypes() {
if (StringUtils.isBlank(accountTypes)) {
return Bundle.ResultDomain_noAccountTypes();
}
return accountTypes;
}
@Override
public long getDataSourceObjectId() {
return this.dataSourceId;

View File

@ -59,13 +59,12 @@ DomainDetailsPanel.miniTimelineTitle.text=Timeline
DomainSummaryPanel.activity.text=Activity: {0} to {1}
DomainSummaryPanel.category.text=Category:
DomainSummaryPanel.downloads.text=Files downloaded:
DomainSummaryPanel.known.text=User role: Known account type(s)
DomainSummaryPanel.loadingImages.text=Loading thumbnail...
DomainSummaryPanel.no.text=No
DomainSummaryPanel.notability.text=Previously tagged as notable:
DomainSummaryPanel.pages.text=Page views in final 60 days:
DomainSummaryPanel.totalPages.text=Total page views:
DomainSummaryPanel.unknown.text=User role: Unknown
DomainSummaryPanel.userRole.text=Account type:
DomainSummaryPanel.yes.text=Yes
GroupsListPanel.noDomainResults.message.text=No domains were found for the selected filters.\n\nReminder:\n -The Recent Activity module must be run on each data source you want to find results in.\n -The Central Repository module must be run on each data source if you want to filter or sort by past occurrences.\n -The iOS Analyzer (iLEAPP) module must be run on each data source which contains data from an iOS device.\n
GroupsListPanel.noFileResults.message.text=No files were found for the selected filters.\n\nReminder:\n -The File Type Identification module must be run on each data source you want to find results in.\n -The Hash Lookup module must be run on each data source if you want to filter by past occurrence.\n -The Picture Analyzer module must be run on each data source if you are filtering by User Created content.

View File

@ -27,20 +27,23 @@
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="domainNameLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="pagesLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="filesDownloadedLabel" linkSize="3" alignment="0" pref="300" max="32767" attributes="0"/>
<Component id="activityLabel" linkSize="3" alignment="0" max="32767" attributes="0"/>
<Component id="totalVisitsLabel" alignment="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="filesDownloadedLabel" linkSize="3" alignment="0" pref="300" max="32767" attributes="0"/>
<Component id="activityLabel" linkSize="3" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="domainNotabilityLabel" pref="300" max="32767" attributes="0"/>
<Component id="domainNotabilityLabel" pref="295" max="32767" attributes="0"/>
<Component id="categoryLabel" max="32767" attributes="0"/>
<Component id="knownAccountTypesLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
</Group>
<Component id="pagesLabel" alignment="0" max="32767" attributes="0"/>
<Component id="totalVisitsLabel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
@ -58,12 +61,12 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="numberOfImagesLabel" min="-2" pref="17" max="-2" attributes="0"/>
<EmptySpace pref="8" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="sampleImageLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="domainNameLabel" min="-2" pref="35" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="32767" attributes="0"/>
<EmptySpace type="unrelated" pref="15" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="activityLabel" linkSize="4" alignment="1" min="-2" pref="15" max="-2" attributes="0"/>
<Component id="domainNotabilityLabel" linkSize="2" alignment="1" min="-2" max="-2" attributes="0"/>
@ -73,8 +76,11 @@
<Component id="filesDownloadedLabel" linkSize="4" pref="14" max="32767" attributes="0"/>
<Component id="categoryLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="totalVisitsLabel" linkSize="2" pref="14" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="totalVisitsLabel" linkSize="2" pref="14" max="32767" attributes="0"/>
<Component id="knownAccountTypesLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="pagesLabel" min="-2" pref="15" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
@ -131,5 +137,7 @@
</Component>
<Component class="javax.swing.JLabel" name="categoryLabel">
</Component>
<Component class="javax.swing.JLabel" name="knownAccountTypesLabel">
</Component>
</SubComponents>
</Form>

View File

@ -1,7 +1,7 @@
/*
* Autopsy
*
* Copyright 2020 Basis Technology Corp.
* Copyright 2020-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -69,6 +69,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
totalVisitsLabel = new javax.swing.JLabel();
domainNotabilityLabel = new javax.swing.JLabel();
categoryLabel = new javax.swing.JLabel();
knownAccountTypesLabel = new javax.swing.JLabel();
setBorder(javax.swing.BorderFactory.createEtchedBorder());
@ -90,17 +91,19 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(domainNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(filesDownloadedLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addComponent(activityLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(totalVisitsLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(filesDownloadedLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addComponent(activityLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(domainNotabilityLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addComponent(categoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(4, 4, 4))
.addComponent(pagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(totalVisitsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(domainNotabilityLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE)
.addComponent(categoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(knownAccountTypesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(4, 4, 4)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(numberOfImagesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -117,11 +120,11 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(numberOfImagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 8, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(sampleImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(domainNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, 15, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(activityLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(domainNotabilityLabel, javax.swing.GroupLayout.Alignment.TRAILING))
@ -129,8 +132,10 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(filesDownloadedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE)
.addComponent(categoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(totalVisitsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE)
.addGap(9, 9, 9)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(totalVisitsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 14, Short.MAX_VALUE)
.addComponent(knownAccountTypesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(pagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(1, 1, 1)))
@ -150,6 +155,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
private javax.swing.JLabel domainNameLabel;
private javax.swing.JLabel domainNotabilityLabel;
private javax.swing.JLabel filesDownloadedLabel;
private javax.swing.JLabel knownAccountTypesLabel;
private javax.swing.JLabel numberOfImagesLabel;
private javax.swing.JLabel pagesLabel;
private javax.swing.JLabel sampleImageLabel;
@ -164,8 +170,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
"DomainSummaryPanel.totalPages.text=Total page views: ",
"DomainSummaryPanel.downloads.text=Files downloaded: ",
"DomainSummaryPanel.notability.text=Previously tagged as notable: ",
"DomainSummaryPanel.unknown.text=User role: Unknown",
"DomainSummaryPanel.known.text=User role: Known account type(s)",
"DomainSummaryPanel.userRole.text=Account type: ",
"DomainSummaryPanel.category.text=Category: ",
"DomainSummaryPanel.loadingImages.text=Loading thumbnail...",
"DomainSummaryPanel.no.text=No",
@ -188,6 +193,7 @@ class DomainSummaryPanel extends javax.swing.JPanel implements ListCellRenderer<
totalVisitsLabel.setText(Bundle.DomainSummaryPanel_totalPages_text() + value.getResultDomain().getTotalPageViews());
pagesLabel.setText(Bundle.DomainSummaryPanel_pages_text() + value.getResultDomain().getPageViewsInLast60Days());
filesDownloadedLabel.setText(Bundle.DomainSummaryPanel_downloads_text() + value.getResultDomain().getFilesDownloaded());
knownAccountTypesLabel.setText(Bundle.DomainSummaryPanel_userRole_text() + value.getResultDomain().getAccountTypes());
if (value.getThumbnail() == null) {
numberOfImagesLabel.setText(Bundle.DomainSummaryPanel_loadingImages_text());
sampleImageLabel.setIcon(null);

View File

@ -323,6 +323,11 @@ abstract class IngestTaskPipeline<T extends IngestTask> {
* performing the task.
*/
abstract void performTask(IngestJobPipeline ingestJobPipeline, T task) throws IngestModuleException;
@Override
public void shutDown() {
module.shutDown();
}
}