formatting, commenting, lat lng terminology corrections

This commit is contained in:
Greg DiCristofaro 2020-11-30 09:35:58 -05:00
parent f986af3543
commit 5ce1a714de
14 changed files with 284 additions and 156 deletions

View File

@ -61,14 +61,14 @@ public class CityRecord extends KdTree.XYZPoint {
* @return Latitude for the city.
*/
public double getLatitude() {
return getX();
return getY();
}
/**
* @return Longitude for the city.
*/
public double getLongitude() {
return getY();
return getX();
}
@Override
@ -104,5 +104,5 @@ public class CityRecord extends KdTree.XYZPoint {
public String toString() {
return "CityRecord{" + "cityName=" + cityName + ", country=" + country + ", lat=" + getX() + ", lng=" + getY() + '}';
}
}

View File

@ -65,7 +65,7 @@ class ClosestCityMapper {
* @return The singleton instance of this class.
* @throws IOException
*/
public static ClosestCityMapper getInstance() throws IOException {
static ClosestCityMapper getInstance() throws IOException {
if (instance == null) {
instance = new ClosestCityMapper();
}
@ -86,7 +86,7 @@ class ClosestCityMapper {
*/
private ClosestCityMapper() throws IOException {
this(
WhereUsedSummary.class.getResourceAsStream(CITIES_CSV_FILENAME),
GeolocationSummary.class.getResourceAsStream(CITIES_CSV_FILENAME),
Logger.getLogger(ClosestCityMapper.class.getName()));
}
@ -157,7 +157,9 @@ class ClosestCityMapper {
/**
* Parses a row from the csv creating a city record.
* @param csvRow The row of data where each item in the list is each column in the row.
*
* @param csvRow The row of data where each item in the list is each column
* in the row.
* @param lineNum The line number for this csv row.
* @return The parsed CityRecord or null if none can be determined.
*/
@ -192,6 +194,7 @@ class ClosestCityMapper {
/**
* Parses a row of the csv into individual column values.
*
* @param line The line to parse.
* @param lineNum The line number in the csv where this line is.
* @return The list of column values.
@ -212,11 +215,14 @@ class ClosestCityMapper {
}
/**
* Parses all lines in the csv file input stream into a list of city records.
* Parses all lines in the csv file input stream into a list of city
* records.
*
* @param csvInputStream The csv file input stream.
* @param ignoreHeaderRow Whether or not there is a header row in the csv file.
* @param ignoreHeaderRow Whether or not there is a header row in the csv
* file.
* @return The list of city records.
* @throws IOException
* @throws IOException
*/
private List<CityRecord> parseCsvLines(InputStream csvInputStream, boolean ignoreHeaderRow) throws IOException {
List<CityRecord> cityRecords = new ArrayList<>();

View File

@ -44,7 +44,7 @@ import org.sleuthkit.datamodel.DataSource;
/**
* Gathers summary data about Geolocation information for a data source.
*/
public class WhereUsedSummary implements DefaultArtifactUpdateGovernor {
public class GeolocationSummary implements DefaultArtifactUpdateGovernor {
/**
* A count of hits for a particular city.
@ -105,33 +105,64 @@ public class WhereUsedSummary implements DefaultArtifactUpdateGovernor {
this.mostRecentSeen = mostRecentSeen;
}
/**
* @return The list of most common cities found in the data source.
*/
public CityCountsList getMostCommon() {
return mostCommon;
}
/**
* @return The list of cities seen in most recent use of data source.
*/
public CityCountsList getMostRecent() {
return mostRecent;
}
/**
* @return The time stamp in seconds from epoch of the most recently
* seen city
*/
public Long getMostRecentSeen() {
return mostRecentSeen;
}
}
/**
* Indicates a list of cities to which way points are closest. Also includes
* the count of way points where no closest city was determined due to not
* being close enough.
*/
public static class CityCountsList {
private final List<CityRecordCount> counts;
private final int otherCount;
public CityCountsList(List<CityRecordCount> counts, int otherCount) {
/**
* Main constructor.
*
* @param counts The list of cities and the count of how many points are
* closest to that city.
* @param otherCount The count of points where no closest city was
* determined due to not being close enough.
*/
CityCountsList(List<CityRecordCount> counts, int otherCount) {
this.counts = Collections.unmodifiableList(new ArrayList<>(counts));
this.otherCount = otherCount;
}
/**
* @return The list of cities and the count of how many points are
* closest to that city.
*/
public List<CityRecordCount> getCounts() {
return counts;
}
/**
* @return The count of points where no closest city was determined due
* to not being close enough.
*/
public int getOtherCount() {
return otherCount;
}
@ -158,19 +189,36 @@ public class WhereUsedSummary implements DefaultArtifactUpdateGovernor {
private final java.util.logging.Logger logger;
private final SupplierWithException<ClosestCityMapper, IOException> cityMapper;
/**
* A supplier of an item T that can throw an exception of type E.
*/
public interface SupplierWithException<T, E extends Throwable> {
/**
* A supplier method that can throw an exception of E.
*
* @return The object type.
* @throws E The exception type.
*/
T get() throws E;
}
/**
* Main constructor.
* Default constructor.
*/
public WhereUsedSummary() {
this(() -> ClosestCityMapper.getInstance(), SleuthkitCaseProvider.DEFAULT, Logger.getLogger(WhereUsedSummary.class.getName()));
public GeolocationSummary() {
this(() -> ClosestCityMapper.getInstance(), SleuthkitCaseProvider.DEFAULT, Logger.getLogger(GeolocationSummary.class.getName()));
}
public WhereUsedSummary(SupplierWithException<ClosestCityMapper, IOException> cityMapper, SleuthkitCaseProvider provider, java.util.logging.Logger logger) {
/**
* Main constructor.
*
* @param cityMapper A means of acquiring a ClosestCityMapper that can throw
* an IOException.
* @param provider A means of acquiring a SleuthkitCaseProvider.
* @param logger The logger.
*/
public GeolocationSummary(SupplierWithException<ClosestCityMapper, IOException> cityMapper, SleuthkitCaseProvider provider, java.util.logging.Logger logger) {
this.cityMapper = cityMapper;
this.provider = provider;
this.logger = logger;
@ -188,6 +236,17 @@ public class WhereUsedSummary implements DefaultArtifactUpdateGovernor {
return GPS_ARTIFACT_TYPE_IDS;
}
/**
* Returns whether or not the time is >= the provided minimum time handling
* the event where either time is null.
*
* @param minTime The minimum time. If null is provided, this function will
* return true.
* @param time The time to check. If null is provided and the min time is
* non-null, then this function will return false.
* @return If minTime == null then true. If minTime != null && time == null
* then false. Otherwise time >= minTime.
*/
private boolean greaterThanOrEqual(Long minTime, Long time) {
if ((minTime == null) || (time != null && time >= minTime)) {
return true;
@ -198,7 +257,16 @@ public class WhereUsedSummary implements DefaultArtifactUpdateGovernor {
private static final Pair<Integer, Integer> EMPTY_COUNT = Pair.of(0, 0);
// left is total count, right is count within time range
/**
* Based on a set of waypoints, determines the count of total waypoints and
* a total of waypoints whose time stamp is greater than or equal to
* minTime.
*
* @param points The list of way points.
* @param minTime The minimum time for most recent points count.
* @return A pair where the left value is the total count of way points and
* the right is the total list of way points that are >= minTime.
*/
private Pair<Integer, Integer> getCounts(List<Waypoint> points, Long minTime) {
if (points == null) {

View File

@ -34,65 +34,84 @@ import org.sleuthkit.autopsy.geolocation.KdTree.XYZPoint;
*/
class LatLngMap<E extends KdTree.XYZPoint> {
// radius of Earth in meters
private static final double EARTH_RADIUS = 6371e3;
// radius of Earth in kilometers
private static final double EARTH_RADIUS = 6371;
// 300 km buckets with 150km accuracy
private static final double BUCKET_SIZE = 300 * 1000;
private static final double DEFAULT_BUCKET_SIZE = 300;
// maps the determined pair of (east/west index, north/south index) to the KdTree containing all items within that bucket.
// maps the determined pair of (north/south index, east/west index) to the KdTree containing all items within that bucket.
private final Map<Pair<Integer, Integer>, KdTree<E>> latLngMap;
private final double bucketSize;
// calculates the bucket for a specific point provided.
private final Function<XYZPoint, Pair<Integer, Integer>> bucketCalculator = (point) -> {
Pair<Double, Double> dPair = getBucketLocation(point);
return Pair.of((int) (double) dPair.getLeft(), (int) (double) dPair.getRight());
};
/**
* Calculates the bucket-normalized pair of (east/west index, north/south
* Contructor.
*
* @param pointsToAdd The points to be added to the data structure.
*/
LatLngMap(List<E> pointsToAdd) {
this(pointsToAdd, DEFAULT_BUCKET_SIZE);
}
/**
* Main contructor.
*
* @param pointsToAdd The points to be added to the data structure.
* @param bucketSize The size of a grid square in kilometers. So, if this
* value is 100, each sqaure will be a 100 x 100 km.
*/
LatLngMap(List<E> pointsToAdd, double bucketSize) {
this.bucketSize = bucketSize;
Map<Pair<Integer, Integer>, List<E>> latLngBuckets = pointsToAdd.stream()
.collect(Collectors.groupingBy((pt) -> bucketCalculator.apply(pt)));
this.latLngMap = latLngBuckets.entrySet().stream()
.map(e -> Pair.of(e.getKey(), new KdTree<E>(e.getValue())))
.collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
}
/**
* Calculates the bucket-normalized pair of (north/south index, east/west
* index) as a double value. For instance, for bucket size 300Km, if a value
* was 450Km east and 150Km north of lng/lat: (0,0), that will translate to
* was 450Km east and 150Km north of lat/lng: (0,0), that will translate to
* (1.5, 0.5). This is used to determine the bucket to search in and the
* closest neighboring buckets.
*
* @param point The point to calculate the bucket location pair.
* @return The pair that was determined.
*/
private static Pair<Double, Double> getBucketLocation(XYZPoint point) {
double y = euclideanDistance(new XYZPoint(0D, 0D), new XYZPoint(0D, point.getY())) / BUCKET_SIZE;
private Pair<Double, Double> getBucketLocation(XYZPoint point) {
double y = euclideanDistance(new XYZPoint(0D, 0D), new XYZPoint(0D, point.getY())) / bucketSize;
if (point.getY() < 0) {
y = -y;
}
double x = euclideanDistance(new XYZPoint(0D, point.getY()), new XYZPoint(point.getX(), point.getY())) / BUCKET_SIZE;
double x = euclideanDistance(new XYZPoint(0D, point.getY()), new XYZPoint(point.getX(), point.getY())) / bucketSize;
if (point.getX() < 0) {
x = -x;
}
return Pair.of(x, y);
}
// calculates the bucket for a specific point provided.
private static final Function<XYZPoint, Pair<Integer, Integer>> bucketCalculator = (point) -> {
Pair<Double, Double> dPair = getBucketLocation(point);
return Pair.of((int) (double) dPair.getLeft(), (int) (double) dPair.getRight());
};
/**
* Main contructor.
* @param pointsToAdd The points to be added to the data structure.
*/
LatLngMap(List<E> pointsToAdd) {
Map<Pair<Integer, Integer>, List<E>> latLngBuckets = pointsToAdd.stream()
.collect(Collectors.groupingBy((pt) -> bucketCalculator.apply(pt)));
latLngMap = latLngBuckets.entrySet().stream()
.map(e -> Pair.of(e.getKey(), new KdTree<E>(e.getValue())))
.collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
return Pair.of(y, x);
}
/**
* Finds closest point within 150Km (.5 * BUCKET_SIZE) distance.
* Finds closest point within (.5 * bucketSize) distance.
*
* @param point The point for which to find closest.
* @return Returns the found point.
*/
E findClosest(E point) {
Pair<Double, Double> calculated = getBucketLocation(point);
// search 2x2 grid around point for closest item. This is done so that if a point is on the
// edge of a grid square and a point in another square is actually closer.
int latBucket = (int) (double) calculated.getLeft();
int latBucket2 = Math.round(calculated.getLeft()) == latBucket ? latBucket - 1 : latBucket + 1;
@ -105,13 +124,14 @@ class LatLngMap<E extends KdTree.XYZPoint> {
E closest4 = findClosestInBucket(latBucket2, lngBucket2, point);
return Stream.of(closest1, closest2, closest3, closest4)
.filter(c -> c != null && euclideanDistance(point, c) <= BUCKET_SIZE / 2)
.filter(c -> c != null && euclideanDistance(point, c) <= bucketSize / 2)
.min((a, b) -> Double.compare(euclideanDistance(point, a), euclideanDistance(point, b)))
.orElse(null);
}
/**
* Within the specific bucket, finds the closest point if any exists.
*
* @param x The x axis bucket.
* @param y The y axis bucket.
* @param point The point to search for.
@ -147,11 +167,11 @@ class LatLngMap<E extends KdTree.XYZPoint> {
return 0;
}
double lat1Radians = Math.toRadians(o1.getX());
double lat2Radians = Math.toRadians(o2.getX());
double lat1Radians = Math.toRadians(o1.getY());
double lat2Radians = Math.toRadians(o2.getY());
double deltaLatRadians = Math.toRadians(o2.getX() - o1.getX());
double deltaLongRadians = Math.toRadians(o2.getY() - o1.getY());
double deltaLatRadians = Math.toRadians(o2.getY() - o1.getY());
double deltaLongRadians = Math.toRadians(o2.getX() - o1.getX());
double a = Math.sin(deltaLatRadians / 2) * Math.sin(deltaLatRadians / 2)
+ Math.cos(lat1Radians) * Math.cos(lat2Radians)

View File

@ -43,9 +43,9 @@ PastCasesPanel.notableFileLabel.text=Cases with Common Items That Were Tagged as
PastCasesPanel.sameIdLabel.text=Past Cases with the Same Device IDs
DataSourceSummaryTabbedPane.noDataSourceLabel.text=No data source has been selected.
TimelinePanel.activityRangeLabel.text=Activity Range
WhereUsedPanel.withinDistanceLabel.text=Locations further than 150Km from a city are not included
WhereUsedPanel.mostRecentLabel.text=Recent Cities from Geolocation Artifacts
WhereUsedPanel.withinDistanceLabel1.text=Locations further than 150Km from a city are not included
WhereUsedPanel.mostCommonLabel.text=Most Common Cities from Geolocation Artifacts
WhereUsedPanel.recentViewInGeolocationBtn.text=View In Geolocation
WhereUsedPanel.commonViewInGeolocationBtn.text=View In Geolocation
GeolocationPanel.withinDistanceLabel.text=Locations further than 150Km from a city are not included
GeolocationPanel.mostRecentLabel.text=Recent Cities from Geolocation Artifacts
GeolocationPanel.withinDistanceLabel1.text=Locations further than 150Km from a city are not included
GeolocationPanel.mostCommonLabel.text=Most Common Cities from Geolocation Artifacts
GeolocationPanel.recentViewInGeolocationBtn.text=View in Map
GeolocationPanel.commonViewInGeolocationBtn.text=View in Map

View File

@ -122,13 +122,13 @@ UserActivityPanel_TopWebSearchTableModel_dateAccessed_header=Date Accessed
UserActivityPanel_TopWebSearchTableModel_searchString_header=Search String
UserActivityPanel_TopWebSearchTableModel_translatedResult_header=Translated
ViewSummaryInformationAction.name.text=View Summary Information
WhereUsedPanel.withinDistanceLabel.text=Locations further than 150Km from a city are not included
WhereUsedPanel.mostRecentLabel.text=Recent Cities from Geolocation Artifacts
WhereUsedPanel.withinDistanceLabel1.text=Locations further than 150Km from a city are not included
WhereUsedPanel.mostCommonLabel.text=Most Common Cities from Geolocation Artifacts
WhereUsedPanel.recentViewInGeolocationBtn.text=View In Geolocation
WhereUsedPanel.commonViewInGeolocationBtn.text=View In Geolocation
WhereUsedPanel_cityColumn_title=Closest City
WhereUsedPanel_countColumn_title=Count
WhereUsedPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.
WhereUsedPanel_unknownRow_title=Unknown
GeolocationPanel.withinDistanceLabel.text=Locations further than 150Km from a city are not included
GeolocationPanel.mostRecentLabel.text=Recent Cities from Geolocation Artifacts
GeolocationPanel.withinDistanceLabel1.text=Locations further than 150Km from a city are not included
GeolocationPanel.mostCommonLabel.text=Most Common Cities from Geolocation Artifacts
GeolocationPanel.recentViewInGeolocationBtn.text=View In Geolocation
GeolocationPanel.commonViewInGeolocationBtn.text=View In Geolocation
GeolocationPanel_cityColumn_title=Closest City
GeolocationPanel_countColumn_title=Count
GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.
GeolocationPanel_unknownRow_title=Unknown

View File

@ -39,7 +39,7 @@ import org.sleuthkit.datamodel.DataSource;
"DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files",
"DataSourceSummaryTabbedPane_pastCasesTab_title=Past Cases",
"DataSourceSummaryTabbedPane_analysisTab_title=Analysis",
"DataSourceSummaryTabbedPane_whereUsedTab_title=Where Used",
"DataSourceSummaryTabbedPane_geolocationTab_title=Geolocation",
"DataSourceSummaryTabbedPane_timelineTab_title=Timeline"
})
public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
@ -125,7 +125,7 @@ public class DataSourceSummaryTabbedPane extends javax.swing.JPanel {
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_analysisTab_title(), new AnalysisPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_pastCasesTab_title(), new PastCasesPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_whereUsedTab_title(), new WhereUsedPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_geolocationTab_title(), new GeolocationPanel()),
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_timelineTab_title(), new TimelinePanel()),
// do nothing on closing
new DataSourceTab(Bundle.DataSourceSummaryTabbedPane_ingestHistoryTab_title(), ingestHistoryPanel, ingestHistoryPanel::setDataSource, () -> {

View File

@ -75,7 +75,7 @@
<Component class="javax.swing.JLabel" name="mostRecentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.mostRecentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.mostRecentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
@ -150,7 +150,7 @@
<Component class="javax.swing.JLabel" name="withinDistanceLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.withinDistanceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.withinDistanceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
@ -180,7 +180,7 @@
<Component class="javax.swing.JButton" name="recentViewInGeolocationBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.recentViewInGeolocationBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.recentViewInGeolocationBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
@ -210,7 +210,7 @@
<Component class="javax.swing.JLabel" name="mostCommonLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.mostCommonLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.mostCommonLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
@ -280,7 +280,7 @@
<Component class="javax.swing.JLabel" name="withinDistanceLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.withinDistanceLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.withinDistanceLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
@ -310,7 +310,7 @@
<Component class="javax.swing.JButton" name="commonViewInGeolocationBtn">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="WhereUsedPanel.commonViewInGeolocationBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="GeolocationPanel.commonViewInGeolocationBtn.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>

View File

@ -29,15 +29,14 @@ import javax.swing.JButton;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.WhereUsedSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.WhereUsedSummary.CityCountsList;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.WhereUsedSummary.CityData;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.WhereUsedSummary.CityRecordCount;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityCountsList;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityData;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.GeolocationSummary.CityRecordCount;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.CityRecord;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
@ -57,11 +56,11 @@ import org.sleuthkit.datamodel.DataSource;
* source's geolocation data.
*/
@Messages({
"WhereUsedPanel_cityColumn_title=Closest City",
"WhereUsedPanel_countColumn_title=Count",
"WhereUsedPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.",
"WhereUsedPanel_unknownRow_title=Unknown",})
public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
"GeolocationPanel_cityColumn_title=Closest City",
"GeolocationPanel_countColumn_title=Count",
"GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.",
"GeolocationPanel_unknownRow_title=Unknown",})
public class GeolocationPanel extends BaseDataSourceSummaryPanel {
private static final long serialVersionUID = 1L;
private static final String GPX_FACTORY = "org.python.proxies.GPX_Parser_Module$GPXParserFileIngestModuleFactory";
@ -69,14 +68,16 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
private static final int DAYS_COUNT = 30;
private static final int MAX_COUNT = 10;
// The column indicating the city
private static final ColumnModel<Pair<String, Integer>> CITY_COL = new ColumnModel<>(
Bundle.WhereUsedPanel_cityColumn_title(),
Bundle.GeolocationPanel_cityColumn_title(),
(pair) -> new DefaultCellModel(pair.getLeft()),
300
);
// The column indicating the count of points seen close to that city
private static final ColumnModel<Pair<String, Integer>> COUNT_COL = new ColumnModel<>(
Bundle.WhereUsedPanel_countColumn_title(),
Bundle.GeolocationPanel_countColumn_title(),
(pair) -> new DefaultCellModel(Integer.toString(pair.getRight())),
100
);
@ -91,20 +92,20 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
// loadable components on this tab
private final List<JTablePanel<?>> tables = Arrays.asList(mostCommonTable, mostRecentTable);
private final Logger logger = Logger.getLogger(WhereUsedPanel.class.getName());
private final Logger logger = Logger.getLogger(GeolocationPanel.class.getName());
// means of fetching and displaying data
private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
private final WhereUsedSummary whereUsedData;
private final GeolocationSummary whereUsedData;
/**
* Main constructor.
*/
public WhereUsedPanel() {
this(new WhereUsedSummary());
public GeolocationPanel() {
this(new GeolocationSummary());
}
/**
@ -112,7 +113,7 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
*
* @param whereUsedData The GeolocationSummary instance to use.
*/
public WhereUsedPanel(WhereUsedSummary whereUsedData) {
public GeolocationPanel(GeolocationSummary whereUsedData) {
this.whereUsedData = whereUsedData;
// set up data acquisition methods
dataFetchComponents = Arrays.asList(
@ -123,6 +124,11 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
initComponents();
}
/**
* Means of rendering data to be shown in the tables.
*
* @param result The result of fetching data for a data source.
*/
private void handleData(DataFetchResult<CityData> result) {
showCityContent(DataFetchResult.getSubResult(result, (dr) -> dr.getMostCommon()), mostCommonTable, commonViewInGeolocationBtn);
showCityContent(DataFetchResult.getSubResult(result, (dr) -> dr.getMostRecent()), mostRecentTable, recentViewInGeolocationBtn);
@ -146,7 +152,14 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
return String.format("%s, %s", record.getCityName(), record.getCountry());
}
private Pair<String, Integer> convert(CityRecordCount cityCount) {
/**
* Formats one record to be displayed as a row in the table (specifically,
* formats the city name).
*
* @param cityCount The CityRecordCount representing a row.
* @return The city/count pair to be displayed as a row.
*/
private Pair<String, Integer> formatRecord(CityRecordCount cityCount) {
if (cityCount == null) {
return null;
}
@ -156,7 +169,16 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
return Pair.of(cityName, count);
}
private List<Pair<String, Integer>> convert(CityCountsList countsList) {
/**
* Formats a list of records to be displayed in a table (specifically,
* includes the count of points where no closest city could be determined as
* 'unknown').
*
* @param countsList The CityCountsList object representing the data to be
* displayed in the table.
* @return The list of city/count tuples to be displayed as a row.
*/
private List<Pair<String, Integer>> formatList(CityCountsList countsList) {
if (countsList == null) {
return null;
}
@ -165,9 +187,9 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
? new ArrayList<CityRecordCount>()
: countsList.getCounts()).stream();
Stream<Pair<String, Integer>> pairStream = countsStream.map((r) -> convert(r));
Stream<Pair<String, Integer>> pairStream = countsStream.map((r) -> formatRecord(r));
Pair<String, Integer> unknownRecord = Pair.of(Bundle.WhereUsedPanel_unknownRow_title(), countsList.getOtherCount());
Pair<String, Integer> unknownRecord = Pair.of(Bundle.GeolocationPanel_unknownRow_title(), countsList.getOtherCount());
return Stream.concat(pairStream, Stream.of(unknownRecord))
.filter((p) -> p != null && p.getRight() != null && p.getRight() > 0)
@ -176,8 +198,15 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
.collect(Collectors.toList());
}
/**
* Shows data in a particular table.
*
* @param result The result to be displayed in the table.
* @param table The table where the data will be displayed.
* @param goToGeolocation The corresponding geolocation navigation button.
*/
private void showCityContent(DataFetchResult<CityCountsList> result, JTablePanel<Pair<String, Integer>> table, JButton goToGeolocation) {
DataFetchResult<List<Pair<String, Integer>>> convertedData = DataFetchResult.getSubResult(result, (countsList) -> convert(countsList));
DataFetchResult<List<Pair<String, Integer>>> convertedData = DataFetchResult.getSubResult(result, (countsList) -> formatList(countsList));
if (convertedData != null && convertedData.getResultType() == DataFetchResult.ResultType.SUCCESS && CollectionUtils.isNotEmpty(convertedData.getData())) {
goToGeolocation.setEnabled(true);
}
@ -185,6 +214,14 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
showResultWithModuleCheck(table, convertedData, GPX_FACTORY, GPX_NAME);
}
/**
* Action to open the geolocation window.
*
* @param dataSource The data source for which the window should filter.
* @param daysLimit The limit for how recently the waypoints should be (for
* most recent table) or null for most recent filter to not be set (for most
* common table).
*/
private void openGeolocationWindow(DataSource dataSource, Integer daysLimit) {
// set the filter
TopComponent topComponent = WindowManager.getDefault().findTopComponent(GeolocationTopComponent.class.getSimpleName());
@ -211,6 +248,9 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
}
}
/**
* Disables navigation buttons.
*/
private void disableNavButtons() {
commonViewInGeolocationBtn.setEnabled(false);
recentViewInGeolocationBtn.setEnabled(false);
@ -272,9 +312,9 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25));
mainContentPanel.add(ingestRunningPanel);
org.openide.awt.Mnemonics.setLocalizedText(mostRecentLabel, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.mostRecentLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(mostRecentLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostRecentLabel.text")); // NOI18N
mainContentPanel.add(mostRecentLabel);
mostRecentLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
mostRecentLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
filler1.setAlignmentX(0.0F);
mainContentPanel.add(filler1);
@ -288,13 +328,13 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
filler2.setAlignmentX(0.0F);
mainContentPanel.add(filler2);
org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.withinDistanceLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel.text")); // NOI18N
mainContentPanel.add(withinDistanceLabel);
filler3.setAlignmentX(0.0F);
mainContentPanel.add(filler3);
org.openide.awt.Mnemonics.setLocalizedText(recentViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.recentViewInGeolocationBtn.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(recentViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.recentViewInGeolocationBtn.text")); // NOI18N
recentViewInGeolocationBtn.setEnabled(false);
recentViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -306,7 +346,7 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
filler8.setAlignmentX(0.0F);
mainContentPanel.add(filler8);
org.openide.awt.Mnemonics.setLocalizedText(mostCommonLabel, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.mostCommonLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(mostCommonLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostCommonLabel.text")); // NOI18N
mainContentPanel.add(mostCommonLabel);
filler7.setAlignmentX(0.0F);
@ -321,13 +361,13 @@ public class WhereUsedPanel extends BaseDataSourceSummaryPanel {
filler6.setAlignmentX(0.0F);
mainContentPanel.add(filler6);
org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel1, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.withinDistanceLabel1.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel1, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel1.text")); // NOI18N
mainContentPanel.add(withinDistanceLabel1);
filler4.setAlignmentX(0.0F);
mainContentPanel.add(filler4);
org.openide.awt.Mnemonics.setLocalizedText(commonViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(WhereUsedPanel.class, "WhereUsedPanel.commonViewInGeolocationBtn.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commonViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.commonViewInGeolocationBtn.text")); // NOI18N
commonViewInGeolocationBtn.setEnabled(false);
commonViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {

View File

@ -71,17 +71,16 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
}
/**
* Called after all of the MapWaypoints are created from all of the
* TSK_GPS_XXX objects.
*
*
* @param mapWaypoints List of filtered MapWaypoints.
* @param tracks The tracks that were successfully parsed.
* @param wasEntirelySuccessful True if no errors occurred while processing.
*/
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks,
boolean wasEntirelySuccessful);
abstract void handleFilteredWaypointSet(Set<MapWaypoint> mapWaypoints, List<Set<MapWaypoint>> tracks,
boolean wasEntirelySuccessful);
@Override
public void process(GeoLocationParseResult<Waypoint> waypointResults) {
@ -93,12 +92,11 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
logger.log(Level.WARNING, "Exception thrown while retrieving list of Tracks", ex);
}
}
Pair<List<Waypoint>, List<List<Waypoint>>> waypointsAndTracks = createWaypointList(
waypointResults.getItems(),
(trackResults == null) ? new ArrayList<Track>() : trackResults.getItems());
Pair<List<Waypoint>, List<List<Waypoint>>> waypointsAndTracks = createWaypointList(
waypointResults.getItems(),
(trackResults == null) ? new ArrayList<Track>() : trackResults.getItems());
final Set<MapWaypoint> pointSet = MapWaypoint.getWaypoints(waypointsAndTracks.getKey());
final List<Set<MapWaypoint>> trackSets = new ArrayList<>();
for (List<Waypoint> t : waypointsAndTracks.getValue()) {
@ -106,8 +104,8 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
}
handleFilteredWaypointSet(
pointSet, trackSets,
(trackResults == null || trackResults.isSuccessfullyParsed()) && waypointResults.isSuccessfullyParsed());
pointSet, trackSets,
(trackResults == null || trackResults.isSuccessfullyParsed()) && waypointResults.isSuccessfullyParsed());
}
/**
@ -115,10 +113,10 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
* account the current filters and includes waypoints as approprate.
*
* @param waypoints List of waypoints
* @param tracks List of tracks
* @param tracks List of tracks
*
* @return A list of waypoints including the tracks based on the current
* filters.
* filters.
*/
private Pair<List<Waypoint>, List<List<Waypoint>>> createWaypointList(List<Waypoint> waypoints, List<Track> tracks) {
final List<Waypoint> completeList = new ArrayList<>();
@ -134,7 +132,7 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
timeRangeStart = timeRangeEnd - (86400 * filters.getMostRecentNumDays());
completeList.addAll(getWaypointsInRange(timeRangeStart, timeRangeEnd, waypoints));
filteredTracks = getTracksInRange(timeRangeStart, timeRangeEnd, tracks);
for (List<Waypoint> filteredTrack : filteredTracks) {
completeList.addAll(filteredTrack);
@ -156,8 +154,8 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
* Return a list of waypoints that fall into the given time range.
*
* @param timeRangeStart start timestamp of range (seconds from java epoch)
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
* @param waypoints List of waypoints to filter.
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
* @param waypoints List of waypoints to filter.
*
* @return A list of waypoints that fall into the time range.
*/
@ -178,16 +176,16 @@ abstract class AbstractWaypointFetcher implements WaypointBuilder.WaypointFilter
}
/**
* Return a list of lists of waypoints from the given tracks that fall into
* Return a list of lists of waypoints from the given tracks that fall into
* the given time range. The track start time will used for determining if
* the whole track falls into the range.
*
* @param timeRangeStart start timestamp of range (seconds from java epoch)
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
* @param tracks Track list.
* @param timeRangeEnd start timestamp of range (seconds from java epoch)
* @param tracks Track list.
*
* @return A list of lists of waypoints corresponding to belong to tracks
* that exist within the time range.
* that exist within the time range.
*/
private List<List<Waypoint>> getTracksInRange(Long timeRangeStart, Long timeRangeEnd, List<Track> tracks) {
List<List<Waypoint>> ret = new ArrayList<>();

View File

@ -40,15 +40,14 @@ public final class GeoFilter {
*
* withoutTimeStamp is only applicable if mostRecentNumDays is true.
*
* When using the filters "most recent days" means to include waypoints
* for the numbers of days after the most recent waypoint, not the
* current date.
* When using the filters "most recent days" means to include waypoints for
* the numbers of days after the most recent waypoint, not the current date.
*
* @param showAll True if all waypoints should be shown
* @param withoutTimeStamp True to show waypoints without timeStamps,
* this filter is only applicable if mostRecentNumDays is true
* @param mostRecentNumDays Show Waypoint for the most recent given
* number of days. This parameter is ignored if showAll is true.
* @param withoutTimeStamp True to show waypoints without timeStamps, this
* filter is only applicable if mostRecentNumDays is true
* @param mostRecentNumDays Show Waypoint for the most recent given number
* of days. This parameter is ignored if showAll is true.
* @param dataSources A list of dataSources to filter waypoint for.
* @param artifactTypes A list of artifactTypes to filter waypoint for.
*/
@ -81,8 +80,8 @@ public final class GeoFilter {
}
/**
* Returns the number of most recent days to show waypoints for. This
* value should be ignored if showAll is true.
* Returns the number of most recent days to show waypoints for. This value
* should be ignored if showAll is true.
*
* @return The number of most recent days to show waypoints for
*/
@ -91,8 +90,8 @@ public final class GeoFilter {
}
/**
* Returns a list of data sources to filter the waypoints by, or null if
* all datasources should be include.
* Returns a list of data sources to filter the waypoints by, or null if all
* datasources should be include.
*
* @return A list of dataSources or null if all dataSources should be
* included.
@ -102,14 +101,14 @@ public final class GeoFilter {
}
/**
* Returns a list of artifact types to filter the waypoints by, or null
* if all types should be include.
* Returns a list of artifact types to filter the waypoints by, or null if
* all types should be include.
*
* @return A list of artifactTypes or null if all artifactTypes should
* be included.
* @return A list of artifactTypes or null if all artifactTypes should be
* included.
*/
List<BlackboardArtifact.ARTIFACT_TYPE> getArtifactTypes() {
return Collections.unmodifiableList(artifactTypes);
}
}

View File

@ -26,7 +26,6 @@ import java.awt.image.BufferedImage;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

View File

@ -216,12 +216,12 @@ public final class GeolocationTopComponent extends TopComponent {
if (filter == null) {
throw new GeoLocationUIException("Filter provided cannot be null.");
}
if (this.isOpened()) {
geoFilterPanel.setupFilter(filter);
updateWaypoints();
} else {
geoFilterPanel.setInitialFilterState(filter);
geoFilterPanel.setInitialFilterState(filter);
}
}

View File

@ -120,14 +120,12 @@ public class KdTree<T extends KdTree.XYZPoint> implements Iterable<T> {
}
/**
* Recursively creates balanced KdNode's from the given list.
* NOTE: The approach is to:
* 1) sort the list based on the depth's comparator
* 2) find a center point
* 3) For lesser and greater, recurse until base case.
*
* There may be more efficient means of achieving balanced nodes.
*
* Recursively creates balanced KdNode's from the given list. NOTE: The
* approach is to: 1) sort the list based on the depth's comparator 2) find
* a center point 3) For lesser and greater, recurse until base case.
*
* There may be more efficient means of achieving balanced nodes.
*
* @param parent The parent of this node or null if this will be root.
* @param points The points to be balanced in the tree.
* @param depth The current depth (used to determine axis to sort on).
@ -636,12 +634,12 @@ public class KdTree<T extends KdTree.XYZPoint> implements Iterable<T> {
/**
* Constructs a new XYZPoint.
*
* @param latitude
* @param longitude
* @param x
* @param y
*/
public XYZPoint(Double latitude, Double longitude) {
x = latitude;
y = longitude;
public XYZPoint(Double x, Double y) {
this.x = x;
this.y = y;
z = 0;
}