Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
GeolocationPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.datasourcesummary.ui;
20 
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29 import javax.swing.JButton;
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.commons.lang3.tuple.Pair;
33 import org.openide.util.NbBundle.Messages;
34 import org.openide.util.actions.CallableSystemAction;
35 import org.openide.windows.TopComponent;
36 import org.openide.windows.WindowManager;
53 import org.sleuthkit.datamodel.DataSource;
54 
59 @Messages({
60  "GeolocationPanel_cityColumn_title=Closest City",
61  "GeolocationPanel_countColumn_title=Count",
62  "GeolocationPanel_onNoCrIngest_message=No results will be shown because the GPX Parser was not run.",
63  "GeolocationPanel_unknownRow_title=Unknown",
64  "GeolocationPanel_mostCommon_tabName=Most Common Cities",
65  "GeolocationPanel_mostRecent_tabName=Most Recent Cities",})
66 public class GeolocationPanel extends BaseDataSourceSummaryPanel {
67 
71  private static class GeolocationViewModel {
72 
73  private final List<Pair<String, Integer>> mostRecentData;
74  private final List<Pair<String, Integer>> mostCommonData;
75 
84  GeolocationViewModel(List<Pair<String, Integer>> mostRecentData, List<Pair<String, Integer>> mostCommonData) {
85  this.mostRecentData = mostRecentData;
86  this.mostCommonData = mostCommonData;
87  }
88 
94  List<Pair<String, Integer>> getMostRecentData() {
95  return mostRecentData;
96  }
97 
103  List<Pair<String, Integer>> getMostCommonData() {
104  return mostCommonData;
105  }
106  }
107 
108  private static final long serialVersionUID = 1L;
109  private static final int DAYS_COUNT = 30;
110  private static final int MAX_COUNT = 10;
111 
112  // The column indicating the city
114  Bundle.GeolocationPanel_cityColumn_title(),
115  (pair) -> new DefaultCellModel<>(pair.getLeft()),
116  300
117  );
118 
119  // The column indicating the count of points seen close to that city
121  Bundle.GeolocationPanel_countColumn_title(),
122  (pair) -> new DefaultCellModel<>(pair.getRight()),
123  100
124  );
125 
126  private static final List<ColumnModel<Pair<String, Integer>, DefaultCellModel<?>>> DEFAULT_TEMPLATE = Arrays.asList(
127  CITY_COL,
128  COUNT_COL
129  );
130 
131  // tables displaying city and number of hits for that city
132  private final JTablePanel<Pair<String, Integer>> mostCommonTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE)
133  .setKeyFunction((pair) -> pair.getLeft());
134 
135  private final JTablePanel<Pair<String, Integer>> mostRecentTable = JTablePanel.getJTablePanel(DEFAULT_TEMPLATE)
136  .setKeyFunction((pair) -> pair.getLeft());
137 
138  // loadable components on this tab
139  private final List<JTablePanel<?>> tables = Arrays.asList(mostCommonTable, mostRecentTable);
140 
141  private final Logger logger = Logger.getLogger(GeolocationPanel.class.getName());
142 
143  // means of fetching and displaying data
144  private final List<DataFetchComponents<DataSource, ?>> dataFetchComponents;
145 
146  private final IngestRunningLabel ingestRunningLabel = new IngestRunningLabel();
147 
149 
151 
155  public GeolocationPanel() {
156  this(new GeolocationSummaryGetter());
157  }
158 
165  super(whereUsedData);
166 
167  this.whereUsedData = whereUsedData;
168 
169  this.geolocationFetcher = (dataSource) -> convertToViewModel(whereUsedData.getCityCounts(dataSource, DAYS_COUNT, MAX_COUNT));
170 
171  // set up data acquisition methods
172  dataFetchComponents = Arrays.asList(
174  geolocationFetcher,
175  (result) -> handleData(result)));
176 
177  initComponents();
178  }
179 
187  showCityContent(DataFetchResult.getSubResult(result, (dr) -> dr.getMostCommonData()), mostCommonTable, commonViewInGeolocationBtn);
188  showCityContent(DataFetchResult.getSubResult(result, (dr) -> dr.getMostRecentData()), mostRecentTable, recentViewInGeolocationBtn);
189  }
190 
198  private static String getCityName(CityRecord record) {
199  if (record == null) {
200  return null;
201  }
202 
203  List<String> cityIdentifiers = Stream.of(record.getCityName(), record.getState(), record.getCountry())
204  .filter(StringUtils::isNotBlank)
205  .collect(Collectors.toList());
206 
207  if (cityIdentifiers.size() == 1) {
208  return cityIdentifiers.get(0);
209  } else if (cityIdentifiers.size() == 2) {
210  return String.format("%s, %s", cityIdentifiers.get(0), cityIdentifiers.get(1));
211  } else if (cityIdentifiers.size() >= 3) {
212  return String.format("%s, %s; %s", cityIdentifiers.get(0), cityIdentifiers.get(1), cityIdentifiers.get(2));
213  }
214 
215  return null;
216  }
217 
226  private Pair<String, Integer> formatRecord(CityRecordCount cityCount) {
227  if (cityCount == null) {
228  return null;
229  }
230 
231  String cityName = getCityName(cityCount.getCityRecord());
232  int count = cityCount.getCount();
233  return Pair.of(cityName, count);
234  }
235 
246  private List<Pair<String, Integer>> formatList(CityCountsList countsList) {
247  if (countsList == null) {
248  return Collections.emptyList();
249  }
250 
251  Stream<CityRecordCount> countsStream = ((countsList.getCounts() == null)
252  ? new ArrayList<CityRecordCount>()
253  : countsList.getCounts()).stream();
254 
255  Stream<Pair<String, Integer>> pairStream = countsStream.map((r) -> formatRecord(r));
256 
257  Pair<String, Integer> unknownRecord = Pair.of(Bundle.GeolocationPanel_unknownRow_title(), countsList.getOtherCount());
258 
259  return Stream.concat(pairStream, Stream.of(unknownRecord))
260  .filter((p) -> p != null && p.getRight() != null && p.getRight() > 0)
261  .sorted((a, b) -> -Integer.compare(a.getRight(), b.getRight()))
262  .limit(MAX_COUNT)
263  .collect(Collectors.toList());
264  }
265 
275  if (cityData == null) {
276  return new GeolocationViewModel(Collections.emptyList(), Collections.emptyList());
277  } else {
278  return new GeolocationViewModel(formatList(cityData.getMostRecent()), formatList(cityData.getMostCommon()));
279  }
280  }
281 
289  private void showCityContent(DataFetchResult<List<Pair<String, Integer>>> result, JTablePanel<Pair<String, Integer>> table, JButton goToGeolocation) {
290  if (result != null && result.getResultType() == DataFetchResult.ResultType.SUCCESS && CollectionUtils.isNotEmpty(result.getData())) {
291  goToGeolocation.setEnabled(true);
292  }
293 
294  table.showDataFetchResult(result);
295  }
296 
305  private void openGeolocationWindow(DataSource dataSource, Integer daysLimit) {
306  // notify dialog (if in dialog) should close.
307  notifyParentClose();
308 
309  // set the filter
310  TopComponent topComponent = WindowManager.getDefault().findTopComponent(GeolocationTopComponent.class.getSimpleName());
311  if (topComponent instanceof GeolocationTopComponent) {
312  GeolocationTopComponent geoComponent = (GeolocationTopComponent) topComponent;
313 
314  GeoFilter filter = (daysLimit == null)
315  ? new GeoFilter(true, false, 0, Arrays.asList(dataSource), whereUsedData.getGeoTypes())
316  : new GeoFilter(false, false, DAYS_COUNT, Arrays.asList(dataSource), whereUsedData.getGeoTypes());
317 
318  try {
319  geoComponent.setFilterState(filter);
320  } catch (GeoLocationUIException ex) {
321  logger.log(Level.WARNING, "There was an error setting filters in the GeoLocationTopComponent.", ex);
322  }
323  }
324 
325  // open the window
326  OpenGeolocationAction action = CallableSystemAction.get(OpenGeolocationAction.class);
327  if (action == null) {
328  logger.log(Level.WARNING, "Unable to obtain an OpenGeolocationAction instance from CallableSystemAction.");
329  } else {
330  action.performAction();
331  }
332  }
333 
337  private void disableNavButtons() {
338  commonViewInGeolocationBtn.setEnabled(false);
339  recentViewInGeolocationBtn.setEnabled(false);
340  }
341 
342  @Override
343  protected void fetchInformation(DataSource dataSource) {
344  disableNavButtons();
345  fetchInformation(dataFetchComponents, dataSource);
346  }
347 
348  @Override
349  protected void onNewDataSource(DataSource dataSource) {
350  disableNavButtons();
351  onNewDataSource(dataFetchComponents, tables, dataSource);
352  }
353 
354  @Override
355  public void close() {
356  ingestRunningLabel.unregister();
357  super.close();
358  }
359 
365  @SuppressWarnings("unchecked")
366  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
367  private void initComponents() {
368 
369  javax.swing.JScrollPane mainScrollPane = new javax.swing.JScrollPane();
370  javax.swing.JPanel mainContentPanel = new javax.swing.JPanel();
371  javax.swing.JPanel ingestRunningPanel = ingestRunningLabel;
372  javax.swing.JLabel mostRecentLabel = new javax.swing.JLabel();
373  javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
374  javax.swing.JPanel mostRecentPanel = mostRecentTable;
375  javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
376  javax.swing.JLabel withinDistanceLabel = new javax.swing.JLabel();
377  javax.swing.Box.Filler filler3 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5));
378  recentViewInGeolocationBtn = new javax.swing.JButton();
379  javax.swing.Box.Filler filler8 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20), new java.awt.Dimension(0, 20));
380  javax.swing.JLabel mostCommonLabel = new javax.swing.JLabel();
381  javax.swing.Box.Filler filler7 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
382  javax.swing.JPanel mostCommonPanel = mostCommonTable;
383  javax.swing.Box.Filler filler6 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2), new java.awt.Dimension(0, 2));
384  javax.swing.JLabel withinDistanceLabel1 = new javax.swing.JLabel();
385  javax.swing.Box.Filler filler4 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5));
386  commonViewInGeolocationBtn = new javax.swing.JButton();
387  javax.swing.Box.Filler filler5 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767));
388 
389  mainContentPanel.setBorder(javax.swing.BorderFactory.createEmptyBorder(10, 10, 10, 10));
390  mainContentPanel.setLayout(new javax.swing.BoxLayout(mainContentPanel, javax.swing.BoxLayout.PAGE_AXIS));
391 
392  ingestRunningPanel.setAlignmentX(0.0F);
393  ingestRunningPanel.setMaximumSize(new java.awt.Dimension(32767, 25));
394  ingestRunningPanel.setMinimumSize(new java.awt.Dimension(10, 25));
395  ingestRunningPanel.setPreferredSize(new java.awt.Dimension(10, 25));
396  mainContentPanel.add(ingestRunningPanel);
397 
398  org.openide.awt.Mnemonics.setLocalizedText(mostRecentLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostRecentLabel.text")); // NOI18N
399  mainContentPanel.add(mostRecentLabel);
400  mostRecentLabel.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "PastCasesPanel.notableFileLabel.text")); // NOI18N
401 
402  filler1.setAlignmentX(0.0F);
403  mainContentPanel.add(filler1);
404 
405  mostRecentPanel.setAlignmentX(0.0F);
406  mostRecentPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
407  mostRecentPanel.setMinimumSize(new java.awt.Dimension(100, 106));
408  mostRecentPanel.setPreferredSize(new java.awt.Dimension(100, 106));
409  mainContentPanel.add(mostRecentPanel);
410 
411  filler2.setAlignmentX(0.0F);
412  mainContentPanel.add(filler2);
413 
414  org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel.text")); // NOI18N
415  mainContentPanel.add(withinDistanceLabel);
416 
417  filler3.setAlignmentX(0.0F);
418  mainContentPanel.add(filler3);
419 
420  org.openide.awt.Mnemonics.setLocalizedText(recentViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.recentViewInGeolocationBtn.text")); // NOI18N
421  recentViewInGeolocationBtn.setEnabled(false);
422  recentViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
423  public void actionPerformed(java.awt.event.ActionEvent evt) {
424  recentViewInGeolocationBtnActionPerformed(evt);
425  }
426  });
427  mainContentPanel.add(recentViewInGeolocationBtn);
428 
429  filler8.setAlignmentX(0.0F);
430  mainContentPanel.add(filler8);
431 
432  org.openide.awt.Mnemonics.setLocalizedText(mostCommonLabel, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.mostCommonLabel.text")); // NOI18N
433  mainContentPanel.add(mostCommonLabel);
434 
435  filler7.setAlignmentX(0.0F);
436  mainContentPanel.add(filler7);
437 
438  mostCommonPanel.setAlignmentX(0.0F);
439  mostCommonPanel.setMaximumSize(new java.awt.Dimension(32767, 106));
440  mostCommonPanel.setMinimumSize(new java.awt.Dimension(100, 106));
441  mostCommonPanel.setPreferredSize(new java.awt.Dimension(100, 106));
442  mainContentPanel.add(mostCommonPanel);
443 
444  filler6.setAlignmentX(0.0F);
445  mainContentPanel.add(filler6);
446 
447  org.openide.awt.Mnemonics.setLocalizedText(withinDistanceLabel1, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.withinDistanceLabel1.text")); // NOI18N
448  mainContentPanel.add(withinDistanceLabel1);
449 
450  filler4.setAlignmentX(0.0F);
451  mainContentPanel.add(filler4);
452 
453  org.openide.awt.Mnemonics.setLocalizedText(commonViewInGeolocationBtn, org.openide.util.NbBundle.getMessage(GeolocationPanel.class, "GeolocationPanel.commonViewInGeolocationBtn.text")); // NOI18N
454  commonViewInGeolocationBtn.setEnabled(false);
455  commonViewInGeolocationBtn.addActionListener(new java.awt.event.ActionListener() {
456  public void actionPerformed(java.awt.event.ActionEvent evt) {
457  commonViewInGeolocationBtnActionPerformed(evt);
458  }
459  });
460  mainContentPanel.add(commonViewInGeolocationBtn);
461 
462  filler5.setAlignmentX(0.0F);
463  mainContentPanel.add(filler5);
464 
465  mainScrollPane.setViewportView(mainContentPanel);
466 
467  javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
468  this.setLayout(layout);
469  layout.setHorizontalGroup(
470  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
471  .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
472  );
473  layout.setVerticalGroup(
474  layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
475  .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 746, Short.MAX_VALUE)
476  );
477  }// </editor-fold>//GEN-END:initComponents
478 
479  private void recentViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_recentViewInGeolocationBtnActionPerformed
480  openGeolocationWindow(getDataSource(), DAYS_COUNT);
481  }//GEN-LAST:event_recentViewInGeolocationBtnActionPerformed
482 
483  private void commonViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commonViewInGeolocationBtnActionPerformed
484  openGeolocationWindow(getDataSource(), null);
485  }//GEN-LAST:event_commonViewInGeolocationBtnActionPerformed
486 
487 
488  // Variables declaration - do not modify//GEN-BEGIN:variables
489  private javax.swing.JButton commonViewInGeolocationBtn;
490  private javax.swing.JButton recentViewInGeolocationBtn;
491  // End of variables declaration//GEN-END:variables
492 }
List< Pair< String, Integer > > formatList(CityCountsList countsList)
static< I, O > DataFetchResult< O > getSubResult(DataFetchResult< I > inputResult, Function< I, O > getSubResult)
void recentViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt)
void commonViewInGeolocationBtnActionPerformed(java.awt.event.ActionEvent evt)
void openGeolocationWindow(DataSource dataSource, Integer daysLimit)
static< T, CextendsGuiCellModel > JTablePanel< T > getJTablePanel(List< ColumnModel< T, C >> columns)
final DataFetcher< DataSource, GeolocationViewModel > geolocationFetcher
void showCityContent(DataFetchResult< List< Pair< String, Integer >>> result, JTablePanel< Pair< String, Integer >> table, JButton goToGeolocation)
GeolocationPanel(GeolocationSummaryGetter whereUsedData)
CityData getCityCounts(DataSource dataSource, int daysCount, int maxCount)
GeolocationViewModel convertToViewModel(CityData cityData)
Pair< String, Integer > formatRecord(CityRecordCount cityCount)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
void handleData(DataFetchResult< GeolocationViewModel > result)
final List< DataFetchComponents< DataSource,?> > dataFetchComponents

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.