Moved file type export functionality

This commit is contained in:
Eugene Livis 2021-08-06 17:31:44 -04:00
parent 0aa708388c
commit e948b14c86
9 changed files with 653 additions and 198 deletions

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentutils;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
@ -45,10 +46,12 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
*/
public final class DataSourceInfoUtilities {
public static final String COMMA_FORMAT_STR = "#,###";
public static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
/**
* Gets a count of tsk_files for a particular datasource.
*
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses.
*
@ -56,11 +59,12 @@ public final class DataSourceInfoUtilities {
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfTskFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException {
public static Long getCountOfTskFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException, NoCurrentCaseException {
if (currentDataSource != null) {
return skCase.countFilesWhere(
return Case.getCurrentCaseThrows().getSleuthkitCase().countFilesWhere(
"data_source_obj_id=" + currentDataSource.getId()
+ (StringUtils.isBlank(additionalWhere) ? "" : (" AND " + additionalWhere)));
}
@ -70,7 +74,6 @@ public final class DataSourceInfoUtilities {
/**
* Gets a count of regular files for a particular datasource.
*
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses.
*
@ -78,22 +81,22 @@ public final class DataSourceInfoUtilities {
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfRegularFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException {
public static Long getCountOfRegularFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException, NoCurrentCaseException {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue();
if (StringUtils.isNotBlank(additionalWhere)) {
whereClause += " AND " + additionalWhere;
}
return getCountOfTskFiles(skCase, currentDataSource, whereClause);
return getCountOfTskFiles(currentDataSource, whereClause);
}
/**
* Gets a count of regular non-slack files for a particular datasource.
*
* @param skCase The current SleuthkitCase.
* @param currentDataSource The datasource.
* @param additionalWhere Additional sql where clauses.
*
@ -101,9 +104,10 @@ public final class DataSourceInfoUtilities {
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfRegNonSlackFiles(SleuthkitCase skCase, DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException {
public static Long getCountOfRegNonSlackFiles(DataSource currentDataSource, String additionalWhere)
throws TskCoreException, SQLException, NoCurrentCaseException {
String whereClause = "meta_type=" + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
+ " AND type<>" + TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType();
@ -111,7 +115,7 @@ public final class DataSourceInfoUtilities {
whereClause += " AND " + additionalWhere;
}
return getCountOfTskFiles(skCase, currentDataSource, whereClause);
return getCountOfTskFiles(currentDataSource, whereClause);
}
/**
@ -429,4 +433,27 @@ public final class DataSourceInfoUtilities {
Long longVal = getLongOrNull(artifact, attributeType);
return (longVal == null || longVal == 0) ? null : new Date(longVal * 1000);
}
/**
* Returns the long value or zero if longVal is null.
*
* @param longVal The long value.
*
* @return The long value or 0 if provided value is null.
*/
public static long getLongOrZero(Long longVal) {
return longVal == null ? 0 : longVal;
}
/**
* Returns string value of long with comma separators. If null returns a
* string of '0'.
*
* @param longVal The long value.
*
* @return The string value of the long.
*/
public static String getStringOrZero(Long longVal) {
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
}
}

View File

@ -22,14 +22,11 @@ import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.sleuthkit.autopsy.casemodule.Case;

View File

@ -0,0 +1,182 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 - 2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.contentutils;
import java.awt.Color;
import java.sql.SQLException;
import java.util.Set;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Helper class for getting summary information on the known files present in the
* specified DataSource..
*/
public class TypesSummary {
private TypesSummary() {
}
/**
* Get count of regular files (not directories) in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfFiles(DataSource currentDataSource)
throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource, null);
}
/**
* Get count of allocated files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfAllocatedFiles(DataSource currentDataSource)
throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC));
}
/**
* Get count of unallocated files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfUnallocatedFiles(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC));
}
/**
* Get count of directories in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfDirectories(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfTskFiles(currentDataSource,
"meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
}
/**
* Get count of slack files in a data source.
*
* @param currentDataSource The data source.
*
* @return The count.
*
* @throws TskCoreException
* @throws SQLException
* @throws NoCurrentCaseException
*/
public static Long getCountOfSlackFiles(DataSource currentDataSource)
throws NoCurrentCaseException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegularFiles(currentDataSource,
"type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType());
}
/**
* Information concerning a particular file type category.
*/
public static class FileTypeCategoryData {
private final String label;
private final Set<String> mimeTypes;
private final Color color;
/**
* Main constructor.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
public FileTypeCategoryData(String label, Set<String> mimeTypes, Color color) {
this.label = label;
this.mimeTypes = mimeTypes;
this.color = color;
}
/**
* Constructor that accepts FileTypeCategory.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
public FileTypeCategoryData(String label, FileTypeUtils.FileTypeCategory fileCategory, Color color) {
this(label, fileCategory.getMediaTypes(), color);
}
/**
* @return The label for this category.
*/
public String getLabel() {
return label;
}
/**
* @return The mime types associated with this category.
*/
public Set<String> getMimeTypes() {
return mimeTypes;
}
/**
* @return The color associated with this category.
*/
public Color getColor() {
return color;
}
}
}

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");
@ -21,10 +21,12 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.ingest.IngestManager;
@ -34,11 +36,10 @@ import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Provides methods to query for datasource files by mime type.
* Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary
* functionality into a DefaultArtifactUpdateGovernor used by TypesPanel tab.
*/
public class MimeTypeSummary implements DefaultUpdateGovernor {
private final SleuthkitCaseProvider provider;
public class MimeTypeSummaryGetter implements DefaultUpdateGovernor {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
@ -46,17 +47,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
/**
* Main constructor.
*/
public MimeTypeSummary() {
this(SleuthkitCaseProvider.DEFAULT);
}
/**
* Main constructor.
*
* @param provider The means of obtaining a sleuthkit case.
*/
public MimeTypeSummary(SleuthkitCaseProvider provider) {
this.provider = provider;
public MimeTypeSummaryGetter() {
}
@Override
@ -76,7 +67,7 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
@Override
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
return INGEST_JOB_EVENTS;
return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
}
/**
@ -99,12 +90,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
provider.get(),
currentDataSource,
"mime_type IN " + getSqlSet(setOfMimeTypes)
);
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes));
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -125,13 +115,13 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfFilesNotInMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
provider.get(),
currentDataSource,
"mime_type NOT IN " + getSqlSet(setOfMimeTypes)
+ " AND mime_type IS NOT NULL AND mime_type <> '' "
);
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource,
"mime_type NOT IN " + getSqlSet(setOfMimeTypes)
+ " AND mime_type IS NOT NULL AND mime_type <> '' ");
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -147,8 +137,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfAllRegularFiles(DataSource dataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), dataSource, null);
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -165,12 +158,11 @@ public class MimeTypeSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfFilesWithNoMimeType(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(
provider.get(),
currentDataSource,
"(mime_type IS NULL OR mime_type = '') "
);
try {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') ");
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**

View File

@ -21,41 +21,31 @@ package org.sleuthkit.autopsy.datasourcesummary.datamodel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DefaultUpdateGovernor;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.contentutils.TypesSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/**
* Provides information for the DataSourceSummaryCountsPanel.
* Wrapper class for converting org.sleuthkit.autopsy.contentutils.TypesSummary functionality into a
* DefaultArtifactUpdateGovernor used by DataSourceSummaryCountsPanel.
*/
public class TypesSummary implements DefaultUpdateGovernor {
public class TypesSummaryGetter implements DefaultUpdateGovernor {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS = new HashSet<>(
Arrays.asList(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED));
private final SleuthkitCaseProvider provider;
/**
* Main constructor.
*/
public TypesSummary() {
this(SleuthkitCaseProvider.DEFAULT);
}
/**
* Main constructor.
*
* @param provider The means of obtaining a sleuthkit case.
*/
public TypesSummary(SleuthkitCaseProvider provider) {
this.provider = provider;
public TypesSummaryGetter() {
}
@Override
@ -75,7 +65,7 @@ public class TypesSummary implements DefaultUpdateGovernor {
@Override
public Set<IngestManager.IngestJobEvent> getIngestJobEventUpdates() {
return INGEST_JOB_EVENTS;
return Collections.unmodifiableSet(INGEST_JOB_EVENTS);
}
/**
@ -91,11 +81,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegularFiles(
provider.get(),
currentDataSource,
null
);
try {
return TypesSummary.getCountOfFiles(currentDataSource);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -111,9 +101,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfAllocatedFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.ALLOC));
try {
return TypesSummary.getCountOfAllocatedFiles(currentDataSource);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -129,9 +121,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfUnallocatedFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(provider.get(), currentDataSource,
DataSourceInfoUtilities.getMetaFlagsContainsStatement(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC));
try {
return TypesSummary.getCountOfUnallocatedFiles(currentDataSource);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -147,10 +141,11 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfDirectories(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfTskFiles(provider.get(), currentDataSource,
"meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType());
try {
return TypesSummary.getCountOfDirectories(currentDataSource);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
/**
@ -166,8 +161,10 @@ public class TypesSummary implements DefaultUpdateGovernor {
*/
public Long getCountOfSlackFiles(DataSource currentDataSource)
throws SleuthkitCaseProvider.SleuthkitCaseProviderException, TskCoreException, SQLException {
return DataSourceInfoUtilities.getCountOfRegularFiles(provider.get(), currentDataSource,
"type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType());
try {
return TypesSummary.getCountOfSlackFiles(currentDataSource);
} catch (NoCurrentCaseException ex) {
throw new SleuthkitCaseProviderException("No currently open case.", ex);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,17 +23,17 @@ import java.sql.SQLException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummary;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.TypesSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.ContainerSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.MimeTypeSummaryGetter;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult.ResultType;
@ -90,7 +90,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* @param usefulContent True if this is useful content; false if there
* is 0 mime type information.
*/
public TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
this.pieSlices = pieSlices;
this.usefulContent = usefulContent;
}
@ -98,78 +98,20 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
/**
* @return The pie chart data.
*/
public List<PieChartItem> getPieSlices() {
List<PieChartItem> getPieSlices() {
return pieSlices;
}
/**
* @return Whether or not the data is usefulContent.
*/
public boolean isUsefulContent() {
boolean isUsefulContent() {
return usefulContent;
}
}
/**
* Information concerning a particular category in the file types pie chart.
*/
private static class TypesPieCategory {
private final String label;
private final Set<String> mimeTypes;
private final Color color;
/**
* Main constructor.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
TypesPieCategory(String label, Set<String> mimeTypes, Color color) {
this.label = label;
this.mimeTypes = mimeTypes;
this.color = color;
}
/**
* Constructor that accepts FileTypeCategory.
*
* @param label The label for this slice.
* @param mimeTypes The mime types associated with this slice.
* @param color The color associated with this slice.
*/
TypesPieCategory(String label, FileTypeCategory fileCategory, Color color) {
this(label, fileCategory.getMediaTypes(), color);
}
/**
* @return The label for this category.
*/
String getLabel() {
return label;
}
/**
* @return The mime types associated with this category.
*/
Set<String> getMimeTypes() {
return mimeTypes;
}
/**
* @return The color associated with this category.
*/
Color getColor() {
return color;
}
}
private static final long serialVersionUID = 1L;
private static final DecimalFormat INTEGER_SIZE_FORMAT = new DecimalFormat("#");
private static final String COMMA_FORMAT_STR = "#,###";
private static final DecimalFormat COMMA_FORMATTER = new DecimalFormat(COMMA_FORMAT_STR);
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
private static final Color VIDEOS_COLOR = Color.YELLOW;
@ -181,13 +123,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
private static final Color NOT_ANALYZED_COLOR = Color.WHITE;
// All file type categories.
private static final List<TypesPieCategory> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
new TypesPieCategory(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
private static final List<FileTypeCategoryData> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
new FileTypeCategoryData(Bundle.TypesPanel_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
);
private final DataFetcher<DataSource, String> usageFetcher;
@ -233,7 +175,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* Creates a new TypesPanel.
*/
public TypesPanel() {
this(new MimeTypeSummary(), new TypesSummary(), new ContainerSummaryGetter());
this(new MimeTypeSummaryGetter(), new TypesSummaryGetter(), new ContainerSummaryGetter());
}
@Override
@ -250,8 +192,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
* @param containerData The service for container information.
*/
public TypesPanel(
MimeTypeSummary mimeTypeData,
TypesSummary typeData,
MimeTypeSummaryGetter mimeTypeData,
TypesSummaryGetter typeData,
ContainerSummaryGetter containerData) {
super(mimeTypeData, typeData, containerData);
@ -277,13 +219,13 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
size -> SizeRepresentationUtil.getSizeString(size, INTEGER_SIZE_FORMAT, false)))),
new DataFetchWorker.DataFetchComponents<>(typesFetcher, this::showMimeTypeCategories),
new DataFetchWorker.DataFetchComponents<>(allocatedFetcher,
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
countRes -> allocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(unallocatedFetcher,
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
countRes -> unallocatedLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(slackFetcher,
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count)))),
countRes -> slackLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count)))),
new DataFetchWorker.DataFetchComponents<>(directoriesFetcher,
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> getStringOrZero(count))))
countRes -> directoriesLabel.showDataFetchResult(DataFetchResult.getSubResult(countRes, (count) -> DataSourceInfoUtilities.getStringOrZero(count))))
);
initComponents();
@ -307,7 +249,7 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
*
* @return The pie chart items.
*/
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummary mimeTypeData, DataSource dataSource)
private TypesPieChartData getMimeTypeCategoriesModel(MimeTypeSummaryGetter mimeTypeData, DataSource dataSource)
throws SQLException, SleuthkitCaseProviderException, TskCoreException {
if (dataSource == null) {
@ -318,8 +260,8 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
List<PieChartItem> fileCategoryItems = new ArrayList<>();
long categoryTotalCount = 0;
for (TypesPieCategory cat : FILE_MIME_TYPE_CATEGORIES) {
long thisValue = getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) {
long thisValue = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
categoryTotalCount += thisValue;
fileCategoryItems.add(new PieChartItem(
@ -329,10 +271,10 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
}
// get a count of all files with no mime type
long noMimeTypeCount = getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource));
long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfFilesWithNoMimeType(dataSource));
// get a count of all regular files
long allRegularFiles = getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource));
long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(mimeTypeData.getCountOfAllRegularFiles(dataSource));
// create entry for mime types in other category
long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount);
@ -385,29 +327,6 @@ class TypesPanel extends BaseDataSourceSummaryPanel {
}
}
/**
* Returns the long value or zero if longVal is null.
*
* @param longVal The long value.
*
* @return The long value or 0 if provided value is null.
*/
private static long getLongOrZero(Long longVal) {
return longVal == null ? 0 : longVal;
}
/**
* Returns string value of long with comma separators. If null returns a
* string of '0'.
*
* @param longVal The long value.
*
* @return The string value of the long.
*/
private static String getStringOrZero(Long longVal) {
return longVal == null ? "0" : COMMA_FORMATTER.format(longVal);
}
/**
* Returns a key value pair to be exported in a sheet.
*

View File

@ -5,6 +5,7 @@ DataSourceSummaryReport.endReport.srcModuleName.text=Excel Report
ExcelExport_writeExcel_noSheetName=Sheet {0}
ExcelExportAction_exportToXLSX_beginExport=Beginning Export...
ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data
ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data
ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data
ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data
ExcelExportAction_exportToXLSX_writingToFile=Writing to File...
@ -32,6 +33,25 @@ ExportRecentFiles_col_header_path=Path
ExportRecentFiles_col_header_sender=Sender
ExportRecentFiles_docsTable_tabName=Recently Opened Documents
ExportRecentFiles_downloadsTable_tabName=Recently Downloads
ExportTypes_artifactsTypesPieChart_title=Artifact Types
ExportTypes_excelTabName=Types
ExportTypes_fileMimeTypesChart_audio_title=Audio
ExportTypes_fileMimeTypesChart_documents_title=Documents
ExportTypes_fileMimeTypesChart_executables_title=Executables
ExportTypes_fileMimeTypesChart_images_title=Images
ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed
ExportTypes_fileMimeTypesChart_other_title=Other
ExportTypes_fileMimeTypesChart_title=File Types
ExportTypes_fileMimeTypesChart_unknown_title=Unknown
ExportTypes_fileMimeTypesChart_valueLabel=Count
ExportTypes_fileMimeTypesChart_videos_title=Videos
ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files
ExportTypes_filesByCategoryTable_directoryRow_title=Directories
ExportTypes_filesByCategoryTable_slackRow_title=Slack Files
ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files
ExportTypes_osLabel_title=OS
ExportTypes_sizeLabel_title=Size
ExportTypes_usageLabel_title=Usage
SizeRepresentationUtil_units_bytes=bytes
SizeRepresentationUtil_units_gigabytes=GB
SizeRepresentationUtil_units_kilobytes=KB

View File

@ -93,6 +93,7 @@ class ExcelExportAction {
"ExcelExportAction_exportToXLSX_gatheringRecentActivityData=Fetching Recent Activity Data",
"ExcelExportAction_exportToXLSX_gatheringContainerData=Fetching Container & Image Data",
"ExcelExportAction_exportToXLSX_gatheringTimelineData=Fetching Timeline Data",
"ExcelExportAction_exportToXLSX_gatheringFileData=Fetching File and MIME Type Data",
"ExcelExportAction_exportToXLSX_writingToFile=Writing to File...",})
void exportToXLSX(ReportProgressPanel progressPanel, DataSource dataSource, String baseReportDir)
@ -127,7 +128,15 @@ class ExcelExportAction {
exports = ExportTimeline.getExports(dataSource);
if (exports != null) {
sheetExports.addAll(exports);
}
}
// Export file and MIME type data
progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_gatheringFileData());
progressPanel.setProgress(4);
exports = ExportTypes.getExports(dataSource);
if (exports != null) {
sheetExports.addAll(exports);
}
progressPanel.updateStatusLabel(Bundle.ExcelExportAction_exportToXLSX_writingToFile());
progressPanel.setProgress(9);

View File

@ -0,0 +1,312 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.report.modules.datasourcesummaryexport;
import java.awt.Color;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.contentutils.ContainerSummary;
import org.sleuthkit.autopsy.coreutils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.autopsy.contentutils.DataSourceInfoUtilities;
import org.sleuthkit.autopsy.contentutils.TypesSummary;
import org.sleuthkit.autopsy.contentutils.TypesSummary.FileTypeCategoryData;
import org.sleuthkit.autopsy.report.modules.datasourcesummaryexport.ExcelSpecialFormatExport.KeyValueItemExportable;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Panel for displaying summary information on the known files present in the
* specified DataSource.
*/
@Messages({
"ExportTypes_artifactsTypesPieChart_title=Artifact Types",
"ExportTypes_filesByCategoryTable_allocatedRow_title=Allocated Files",
"ExportTypes_filesByCategoryTable_unallocatedRow_title=Unallocated Files",
"ExportTypes_filesByCategoryTable_slackRow_title=Slack Files",
"ExportTypes_filesByCategoryTable_directoryRow_title=Directories",
"ExportTypes_fileMimeTypesChart_title=File Types",
"ExportTypes_fileMimeTypesChart_valueLabel=Count",
"ExportTypes_fileMimeTypesChart_audio_title=Audio",
"ExportTypes_fileMimeTypesChart_documents_title=Documents",
"ExportTypes_fileMimeTypesChart_executables_title=Executables",
"ExportTypes_fileMimeTypesChart_images_title=Images",
"ExportTypes_fileMimeTypesChart_videos_title=Videos",
"ExportTypes_fileMimeTypesChart_other_title=Other",
"ExportTypes_fileMimeTypesChart_unknown_title=Unknown",
"ExportTypes_fileMimeTypesChart_notAnalyzed_title=Not Analyzed",
"ExportTypes_usageLabel_title=Usage",
"ExportTypes_osLabel_title=OS",
"ExportTypes_sizeLabel_title=Size",
"ExportTypes_excelTabName=Types"})
class ExportTypes {
/**
* Data for types pie chart.
*/
private static class TypesPieChartData {
private final List<PieChartItem> pieSlices;
private final boolean usefulContent;
/**
* Main constructor.
*
* @param pieSlices The pie slices.
* @param usefulContent True if this is useful content; false if there
* is 0 mime type information.
*/
TypesPieChartData(List<PieChartItem> pieSlices, boolean usefulContent) {
this.pieSlices = pieSlices;
this.usefulContent = usefulContent;
}
/**
* @return The pie chart data.
*/
List<PieChartItem> getPieSlices() {
return pieSlices;
}
/**
* @return Whether or not the data is usefulContent.
*/
boolean isUsefulContent() {
return usefulContent;
}
}
private static final Color IMAGES_COLOR = new Color(156, 39, 176);
private static final Color VIDEOS_COLOR = Color.YELLOW;
private static final Color AUDIO_COLOR = Color.BLUE;
private static final Color DOCUMENTS_COLOR = Color.GREEN;
private static final Color EXECUTABLES_COLOR = new Color(0, 188, 212);
private static final Color UNKNOWN_COLOR = Color.ORANGE;
private static final Color OTHER_COLOR = new Color(78, 52, 46);
private static final Color NOT_ANALYZED_COLOR = Color.WHITE;
// All file type categories.
private static final List<FileTypeCategoryData> FILE_MIME_TYPE_CATEGORIES = Arrays.asList(
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_images_title(), FileTypeCategory.IMAGE.getMediaTypes(), IMAGES_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_videos_title(), FileTypeCategory.VIDEO.getMediaTypes(), VIDEOS_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_audio_title(), FileTypeCategory.AUDIO.getMediaTypes(), AUDIO_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_documents_title(), FileTypeCategory.DOCUMENTS.getMediaTypes(), DOCUMENTS_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_executables_title(), FileTypeCategory.EXECUTABLE.getMediaTypes(), EXECUTABLES_COLOR),
new FileTypeCategoryData(Bundle.ExportTypes_fileMimeTypesChart_unknown_title(), new HashSet<>(Arrays.asList("application/octet-stream")), UNKNOWN_COLOR)
);
private ExportTypes() {
}
/**
* Derives a sql set string (i.e. "('val1', 'val2', 'val3')"). A naive
* attempt is made to sanitize the strings by removing single quotes from
* values.
*
* @param setValues The values that should be present in the set. Single
* quotes are removed.
*
* @return The sql set string.
*/
private static String getSqlSet(Set<String> setValues) {
List<String> quotedValues = setValues
.stream()
.map(str -> String.format("'%s'", str.replace("'", "")))
.collect(Collectors.toList());
String commaSeparatedQuoted = String.join(", ", quotedValues);
return String.format("(%s) ", commaSeparatedQuoted);
}
/**
* Get the number of files in the case database for the current data source
* which have the specified mimetypes.
*
* @param currentDataSource the data source which we are finding a file
* count
*
* @param setOfMimeTypes the set of mime types which we are finding the
* number of occurences of
*
* @return a Long value which represents the number of occurrences of the
* specified mime types in the current case for the specified data
* source, null if no count was retrieved
*
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws SQLException
*/
private static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set<String> setOfMimeTypes) throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "mime_type IN " + getSqlSet(setOfMimeTypes));
}
/**
* Gets the number of files in the data source with no assigned mime type.
*
* @param currentDataSource The data source.
*
* @return The number of files with no mime type or null if there is an
* issue searching the data source.
*
* @throws NoCurrentCaseException
* @throws TskCoreException
* @throws SQLException
*/
private static Long getCountOfFilesWithNoMimeType(DataSource currentDataSource) throws TskCoreException, SQLException, NoCurrentCaseException {
return DataSourceInfoUtilities.getCountOfRegNonSlackFiles(currentDataSource, "(mime_type IS NULL OR mime_type = '') ");
}
/**
* Gets all the data for the file type pie chart.
*
* @param mimeTypeData The means of acquiring data.
* @param dataSource The datasource.
*
* @return The pie chart items.
*/
private static TypesPieChartData getMimeTypeCategoriesModel(DataSource dataSource)
throws SQLException, TskCoreException, NoCurrentCaseException {
if (dataSource == null) {
return null;
}
// for each category of file types, get the counts of files
List<PieChartItem> fileCategoryItems = new ArrayList<>();
long categoryTotalCount = 0;
for (FileTypeCategoryData cat : FILE_MIME_TYPE_CATEGORIES) {
long thisValue = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesForMimeTypes(dataSource, cat.getMimeTypes()));
categoryTotalCount += thisValue;
fileCategoryItems.add(new PieChartItem(
cat.getLabel(),
thisValue,
cat.getColor()));
}
// get a count of all files with no mime type
long noMimeTypeCount = DataSourceInfoUtilities.getLongOrZero(getCountOfFilesWithNoMimeType(dataSource));
// get a count of all regular files
long allRegularFiles = DataSourceInfoUtilities.getLongOrZero(DataSourceInfoUtilities.getCountOfRegNonSlackFiles(dataSource, null));
// create entry for mime types in other category
long otherCount = allRegularFiles - (categoryTotalCount + noMimeTypeCount);
PieChartItem otherPieItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_other_title(),
otherCount, OTHER_COLOR);
// check at this point to see if these are all 0; if so, we don't have useful content.
boolean usefulContent = categoryTotalCount > 0 || otherCount > 0;
// create entry for not analyzed mime types category
PieChartItem notAnalyzedItem = new PieChartItem(Bundle.ExportTypes_fileMimeTypesChart_notAnalyzed_title(),
noMimeTypeCount, NOT_ANALYZED_COLOR);
// combine categories with 'other' and 'not analyzed'
List<PieChartItem> items = Stream.concat(
fileCategoryItems.stream(),
Stream.of(otherPieItem, notAnalyzedItem))
// remove items that have no value
.filter(slice -> slice.getValue() > 0)
.collect(Collectors.toList());
return new TypesPieChartData(items, usefulContent);
}
/**
* Returns a key value pair to be exported in a sheet.
*
* @param fetcher The means of fetching the data.
* @param key The key to use.
* @param dataSource The data source containing the data.
*
* @return The key value pair to be exported.
*/
private static KeyValueItemExportable getStrExportable(DataFetcher<DataSource, String> fetcher, String key, DataSource dataSource) {
String result = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource);
return (result == null) ? null : new KeyValueItemExportable(key, new DefaultCellModel<>(result));
}
/**
* Returns a key value pair to be exported in a sheet formatting the long
* with commas separated by orders of 1000.
*
* @param fetcher The means of fetching the data.
* @param key The string key for this key value pair.
* @param dataSource The data source.
*
* @return The key value pair.
*/
private static KeyValueItemExportable getCountExportable(DataFetcher<DataSource, Long> fetcher, String key, DataSource dataSource) {
Long count = ExcelExportAction.getFetchResult(fetcher, "Types", dataSource);
return (count == null) ? null : new KeyValueItemExportable(key,
new DefaultCellModel<Long>(count, DataSourceInfoUtilities.COMMA_FORMATTER::format, DataSourceInfoUtilities.COMMA_FORMAT_STR));
}
static List<ExcelExport.ExcelSheetExport> getExports(DataSource dataSource) {
if (dataSource == null) {
return Collections.emptyList();
}
DataFetcher<DataSource, String> usageFetcher = (ds) -> ContainerSummary.getDataSourceType(ds);
DataFetcher<DataSource, String> osFetcher = (ds) -> ContainerSummary.getOperatingSystems(ds);
DataFetcher<DataSource, Long> sizeFetcher = (ds) -> ds == null ? null : ds.getSize();
DataFetcher<DataSource, TypesPieChartData> typesFetcher = (ds) -> getMimeTypeCategoriesModel(ds);
DataFetcher<DataSource, Long> allocatedFetcher = (ds) -> TypesSummary.getCountOfAllocatedFiles(ds);
DataFetcher<DataSource, Long> unallocatedFetcher = (ds) -> TypesSummary.getCountOfUnallocatedFiles(ds);
DataFetcher<DataSource, Long> slackFetcher = (ds) -> TypesSummary.getCountOfSlackFiles(ds);
DataFetcher<DataSource, Long> directoriesFetcher = (ds) -> TypesSummary.getCountOfDirectories(ds);
// Retrieve data to create the types pie chart
TypesPieChartData typesData = ExcelExportAction.getFetchResult(typesFetcher, "Types", dataSource);
PieChartExport typesChart = (typesData == null || !typesData.isUsefulContent()) ? null
: new PieChartExport(
Bundle.ExportTypes_fileMimeTypesChart_title(),
Bundle.ExportTypes_fileMimeTypesChart_valueLabel(),
"#,###",
Bundle.ExportTypes_fileMimeTypesChart_title(),
typesData.getPieSlices());
return Arrays.asList(new ExcelSpecialFormatExport(Bundle.ExportTypes_excelTabName(),
Stream.of(
getStrExportable(usageFetcher, Bundle.ExportTypes_usageLabel_title(), dataSource),
getStrExportable(osFetcher, Bundle.ExportTypes_osLabel_title(), dataSource),
new KeyValueItemExportable(Bundle.ExportTypes_sizeLabel_title(),
SizeRepresentationUtil.getBytesCell(ExcelExportAction.getFetchResult(sizeFetcher, "Types", dataSource))),
typesChart,
getCountExportable(allocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_allocatedRow_title(), dataSource),
getCountExportable(unallocatedFetcher, Bundle.ExportTypes_filesByCategoryTable_unallocatedRow_title(), dataSource),
getCountExportable(slackFetcher, Bundle.ExportTypes_filesByCategoryTable_slackRow_title(), dataSource),
getCountExportable(directoriesFetcher, Bundle.ExportTypes_filesByCategoryTable_directoryRow_title(), dataSource))
.filter(sheet -> sheet != null)
.collect(Collectors.toList())
));
}
}