19 package org.sleuthkit.autopsy.commonfilesearch;
22 import java.sql.ResultSet;
23 import java.sql.SQLException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashMap;
28 import java.util.Map.Entry;
29 import java.util.concurrent.ExecutionException;
30 import java.util.logging.Level;
31 import javax.swing.ComboBoxModel;
32 import javax.swing.SwingUtilities;
33 import javax.swing.SwingWorker;
34 import org.openide.explorer.ExplorerManager;
35 import org.openide.util.NbBundle;
47 import org.
sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
54 @SuppressWarnings(
"PMD.SingularField")
57 private static final long serialVersionUID = 1L;
59 private static final Long NO_DATA_SOURCE_SELECTED = -1L;
65 private boolean singleDataSource =
false;
66 private String selectedDataSource =
"";
74 "CommonFilesPanel.title=Common Files Panel",
75 "CommonFilesPanel.exception=Unexpected Exception loading DataSources."})
79 this.setupDataSources();
81 this.errorText.setVisible(
false);
91 "CommonFilesPanel.buildDataSourceMap.done.tskCoreException=Unable to run query against DB.",
92 "CommonFilesPanel.buildDataSourceMap.done.noCurrentCaseException=Unable to open case file.",
93 "CommonFilesPanel.buildDataSourceMap.done.exception=Unexpected exception building data sources map.",
94 "CommonFilesPanel.buildDataSourceMap.done.interupted=Something went wrong building the Common Files Search dialog box.",
95 "CommonFilesPanel.buildDataSourceMap.done.sqlException=Unable to query db for data sources.",
96 "CommonFilesPanel.buildDataSourcesMap.updateUi.noDataSources=No data sources were found."})
99 new SwingWorker<Map<Long, String>, Void>() {
101 private static final String SELECT_DATA_SOURCES_LOGICAL =
"select obj_id, name from tsk_files where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
103 private static final String SELECT_DATA_SOURCES_IMAGE =
"select obj_id, name from tsk_image_names where obj_id in (SELECT obj_id FROM tsk_objects WHERE obj_id in (select obj_id from data_source_info))";
105 private void updateUi() {
110 if (dataSourcesNames.length > 0) {
115 boolean multipleDataSources = this.caseHasMultipleSources();
119 if (!multipleDataSources) {
121 withinDataSourceSelected(
true);
131 private boolean caseHasMultipleSources() {
135 private void loadLogicalSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap)
throws TskCoreException, SQLException {
138 CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_LOGICAL);
139 ResultSet resultSet = query.getResultSet()) {
140 while (resultSet.next()) {
141 Long objectId = resultSet.getLong(1);
142 String dataSourceName = resultSet.getString(2);
143 dataSouceMap.put(objectId, dataSourceName);
148 private void loadImageSources(SleuthkitCase tskDb, Map<Long, String> dataSouceMap)
throws SQLException, TskCoreException {
151 CaseDbQuery query = tskDb.executeQuery(SELECT_DATA_SOURCES_IMAGE);
152 ResultSet resultSet = query.getResultSet()) {
154 while (resultSet.next()) {
155 Long objectId = resultSet.getLong(1);
156 String dataSourceName = resultSet.getString(2);
157 File image =
new File(dataSourceName);
158 String dataSourceNameTrimmed = image.getName();
159 dataSouceMap.put(objectId, dataSourceNameTrimmed);
165 protected Map<Long, String> doInBackground()
throws NoCurrentCaseException, TskCoreException, SQLException {
167 Map<Long, String> dataSouceMap =
new HashMap<>();
172 loadLogicalSources(tskDb, dataSouceMap);
174 loadImageSources(tskDb, dataSouceMap);
180 protected void done() {
187 }
catch (InterruptedException ex) {
188 LOGGER.log(Level.SEVERE,
"Interrupted while building Common Files Search dialog.", ex);
190 }
catch (ExecutionException ex) {
192 Throwable inner = ex.getCause();
193 if (inner instanceof TskCoreException) {
194 LOGGER.log(Level.SEVERE,
"Failed to load data sources from database.", ex);
195 errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_tskCoreException();
196 }
else if (inner instanceof NoCurrentCaseException) {
197 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
198 errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_noCurrentCaseException();
199 }
else if (inner instanceof SQLException) {
200 LOGGER.log(Level.SEVERE,
"Unable to query db for data sources.", ex);
201 errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_sqlException();
203 LOGGER.log(Level.SEVERE,
"Unexpected exception while building Common Files Search dialog panel.", ex);
204 errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_exception();
213 "CommonFilesPanel.search.results.titleAll=Common Files (All Data Sources)",
214 "CommonFilesPanel.search.results.titleSingle=Common Files (Match Within Data Source: %s)",
215 "CommonFilesPanel.search.results.pathText=Common Files Search Results",
216 "CommonFilesPanel.search.done.tskCoreException=Unable to run query against DB.",
217 "CommonFilesPanel.search.done.noCurrentCaseException=Unable to open case file.",
218 "CommonFilesPanel.search.done.exception=Unexpected exception running Common Files Search.",
219 "CommonFilesPanel.search.done.interupted=Something went wrong finding common files.",
220 "CommonFilesPanel.search.done.sqlException=Unable to query db for files or data sources."})
222 String pathText = Bundle.CommonFilesPanel_search_results_pathText();
224 new SwingWorker<CommonFilesMetadata, Void>() {
226 private String tabTitle;
228 private void setTitleForAllDataSources() {
229 this.tabTitle = Bundle.CommonFilesPanel_search_results_titleAll();
232 private void setTitleForSingleSource(Long dataSourceId) {
233 final String CommonFilesPanel_search_results_titleSingle = Bundle.CommonFilesPanel_search_results_titleSingle();
234 final Object[] dataSourceName =
new Object[]{dataSourceMap.get(dataSourceId)};
236 this.tabTitle = String.format(CommonFilesPanel_search_results_titleSingle, dataSourceName);
239 private Long determineDataSourceId() {
244 selectedObjId = dataSource.getKey();
249 return selectedObjId;
253 @SuppressWarnings({
"BoxedValueEquality",
"NumberEquality"})
254 protected CommonFilesMetadata doInBackground()
throws TskCoreException,
NoCurrentCaseException, SQLException {
255 Long dataSourceId = determineDataSourceId();
257 CommonFilesMetadataBuilder builder;
258 boolean filterByMedia =
false;
259 boolean filterByDocuments =
false;
260 if (selectedFileCategoriesButton.isSelected()) {
261 if (pictureVideoCheckbox.isSelected()) {
262 filterByMedia =
true;
264 if (documentsCheckbox.isSelected()) {
265 filterByDocuments =
true;
271 setTitleForAllDataSources();
275 setTitleForSingleSource(dataSourceId);
278 this.tabTitle = builder.buildTabTitle();
280 CommonFilesMetadata metadata = builder.findCommonFiles();
286 protected void done() {
290 CommonFilesMetadata metadata =
get();
300 Collection<DataResultViewer> viewers =
new ArrayList<>(1);
305 }
catch (InterruptedException ex) {
306 LOGGER.log(Level.SEVERE,
"Interrupted while loading Common Files", ex);
308 }
catch (ExecutionException ex) {
310 Throwable inner = ex.getCause();
311 if (inner instanceof TskCoreException) {
312 LOGGER.log(Level.SEVERE,
"Failed to load files from database.", ex);
313 errorMessage = Bundle.CommonFilesPanel_search_done_tskCoreException();
314 }
else if (inner instanceof NoCurrentCaseException) {
315 LOGGER.log(Level.SEVERE,
"Current case has been closed.", ex);
316 errorMessage = Bundle.CommonFilesPanel_search_done_noCurrentCaseException();
317 }
else if (inner instanceof SQLException) {
318 LOGGER.log(Level.SEVERE,
"Unable to query db for files.", ex);
319 errorMessage = Bundle.CommonFilesPanel_search_done_sqlException();
321 LOGGER.log(Level.SEVERE,
"Unexpected exception while running Common Files Search.", ex);
322 errorMessage = Bundle.CommonFilesPanel_search_done_exception();
335 @SuppressWarnings(
"unchecked")
337 private
void initComponents() {
339 dataSourcesButtonGroup =
new javax.swing.ButtonGroup();
340 fileTypeFilterButtonGroup =
new javax.swing.ButtonGroup();
341 searchButton =
new javax.swing.JButton();
342 allDataSourcesRadioButton =
new javax.swing.JRadioButton();
343 withinDataSourceRadioButton =
new javax.swing.JRadioButton();
344 selectDataSourceComboBox =
new javax.swing.JComboBox<>();
345 commonFilesSearchLabel =
new javax.swing.JLabel();
346 cancelButton =
new javax.swing.JButton();
347 allFileCategoriesRadioButton =
new javax.swing.JRadioButton();
348 selectedFileCategoriesButton =
new javax.swing.JRadioButton();
349 pictureVideoCheckbox =
new javax.swing.JCheckBox();
350 documentsCheckbox =
new javax.swing.JCheckBox();
351 dataSourceLabel =
new javax.swing.JLabel();
352 categoriesLabel =
new javax.swing.JLabel();
353 errorText =
new javax.swing.JLabel();
355 org.openide.awt.Mnemonics.setLocalizedText(searchButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.searchButton.text"));
356 searchButton.setEnabled(
false);
357 searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
358 searchButton.addActionListener(
new java.awt.event.ActionListener() {
359 public void actionPerformed(java.awt.event.ActionEvent evt) {
360 searchButtonActionPerformed(evt);
364 dataSourcesButtonGroup.add(allDataSourcesRadioButton);
365 allDataSourcesRadioButton.setSelected(
true);
366 org.openide.awt.Mnemonics.setLocalizedText(allDataSourcesRadioButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.allDataSourcesRadioButton.text"));
367 allDataSourcesRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
368 allDataSourcesRadioButton.addActionListener(
new java.awt.event.ActionListener() {
369 public void actionPerformed(java.awt.event.ActionEvent evt) {
370 allDataSourcesRadioButtonActionPerformed(evt);
374 dataSourcesButtonGroup.add(withinDataSourceRadioButton);
375 org.openide.awt.Mnemonics.setLocalizedText(withinDataSourceRadioButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.withinDataSourceRadioButton.text"));
376 withinDataSourceRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
377 withinDataSourceRadioButton.addActionListener(
new java.awt.event.ActionListener() {
378 public void actionPerformed(java.awt.event.ActionEvent evt) {
379 withinDataSourceRadioButtonActionPerformed(evt);
383 selectDataSourceComboBox.setModel(dataSourcesList);
384 selectDataSourceComboBox.setEnabled(
false);
385 selectDataSourceComboBox.addActionListener(
new java.awt.event.ActionListener() {
386 public void actionPerformed(java.awt.event.ActionEvent evt) {
387 selectDataSourceComboBoxActionPerformed(evt);
391 org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.commonFilesSearchLabel.text"));
392 commonFilesSearchLabel.setFocusable(
false);
394 org.openide.awt.Mnemonics.setLocalizedText(cancelButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.cancelButton.text"));
395 cancelButton.setActionCommand(
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.cancelButton.actionCommand"));
396 cancelButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
397 cancelButton.addActionListener(
new java.awt.event.ActionListener() {
398 public void actionPerformed(java.awt.event.ActionEvent evt) {
399 cancelButtonActionPerformed(evt);
403 fileTypeFilterButtonGroup.add(allFileCategoriesRadioButton);
404 org.openide.awt.Mnemonics.setLocalizedText(allFileCategoriesRadioButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.allFileCategoriesRadioButton.text"));
405 allFileCategoriesRadioButton.setToolTipText(
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.allFileCategoriesRadioButton.toolTipText"));
406 allFileCategoriesRadioButton.addActionListener(
new java.awt.event.ActionListener() {
407 public void actionPerformed(java.awt.event.ActionEvent evt) {
408 allFileCategoriesRadioButtonActionPerformed(evt);
412 fileTypeFilterButtonGroup.add(selectedFileCategoriesButton);
413 selectedFileCategoriesButton.setSelected(
true);
414 org.openide.awt.Mnemonics.setLocalizedText(selectedFileCategoriesButton,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.selectedFileCategoriesButton.text"));
415 selectedFileCategoriesButton.setToolTipText(
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.selectedFileCategoriesButton.toolTipText"));
416 selectedFileCategoriesButton.addActionListener(
new java.awt.event.ActionListener() {
417 public void actionPerformed(java.awt.event.ActionEvent evt) {
418 selectedFileCategoriesButtonActionPerformed(evt);
422 pictureVideoCheckbox.setSelected(
true);
423 org.openide.awt.Mnemonics.setLocalizedText(pictureVideoCheckbox,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.pictureVideoCheckbox.text"));
424 pictureVideoCheckbox.addActionListener(
new java.awt.event.ActionListener() {
425 public void actionPerformed(java.awt.event.ActionEvent evt) {
426 pictureVideoCheckboxActionPerformed(evt);
430 documentsCheckbox.setSelected(
true);
431 org.openide.awt.Mnemonics.setLocalizedText(documentsCheckbox,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.documentsCheckbox.text"));
432 documentsCheckbox.addActionListener(
new java.awt.event.ActionListener() {
433 public void actionPerformed(java.awt.event.ActionEvent evt) {
434 documentsCheckboxActionPerformed(evt);
438 org.openide.awt.Mnemonics.setLocalizedText(dataSourceLabel,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.text"));
439 dataSourceLabel.setName(
"");
441 org.openide.awt.Mnemonics.setLocalizedText(categoriesLabel,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.categoriesLabel.text"));
442 categoriesLabel.setName(
"");
444 errorText.setForeground(
new java.awt.Color(255, 0, 0));
445 org.openide.awt.Mnemonics.setLocalizedText(errorText,
org.openide.util.NbBundle.getMessage(
CommonFilesPanel.class,
"CommonFilesPanel.errorText.text"));
447 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
448 this.setLayout(layout);
449 layout.setHorizontalGroup(
450 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
451 .addGroup(layout.createSequentialGroup()
453 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING,
false)
454 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
455 .addComponent(errorText)
456 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
457 .addComponent(searchButton)
458 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
459 .addComponent(cancelButton)
461 .addGroup(layout.createSequentialGroup()
462 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
463 .addComponent(categoriesLabel)
464 .addComponent(commonFilesSearchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
465 .addComponent(dataSourceLabel)
466 .addGroup(layout.createSequentialGroup()
468 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
469 .addGroup(layout.createSequentialGroup()
471 .addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE))
472 .addComponent(withinDataSourceRadioButton)
473 .addComponent(allDataSourcesRadioButton)
474 .addComponent(allFileCategoriesRadioButton)
475 .addComponent(selectedFileCategoriesButton)
476 .addGroup(layout.createSequentialGroup()
478 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
479 .addComponent(pictureVideoCheckbox)
480 .addComponent(documentsCheckbox))))))
481 .addGap(19, 19, 19))))
483 layout.setVerticalGroup(
484 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
485 .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
487 .addComponent(commonFilesSearchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
489 .addComponent(dataSourceLabel)
490 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
491 .addComponent(allDataSourcesRadioButton)
492 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
493 .addComponent(withinDataSourceRadioButton)
494 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
495 .addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
497 .addComponent(categoriesLabel)
498 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
499 .addComponent(selectedFileCategoriesButton)
500 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
501 .addComponent(pictureVideoCheckbox)
502 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
503 .addComponent(documentsCheckbox)
504 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
505 .addComponent(allFileCategoriesRadioButton)
506 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
507 .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
508 .addComponent(cancelButton)
509 .addComponent(searchButton)
510 .addComponent(errorText)))
516 SwingUtilities.windowForComponent(
this).dispose();
520 selectDataSourceComboBox.setEnabled(!allDataSourcesRadioButton.isSelected());
521 singleDataSource =
false;
525 final Object selectedItem = selectDataSourceComboBox.getSelectedItem();
526 if (selectedItem != null) {
527 selectedDataSource = selectedItem.toString();
529 selectedDataSource =
"";
534 withinDataSourceSelected(withinDataSourceRadioButton.isSelected());
538 SwingUtilities.windowForComponent(
this).dispose();
542 this.manageCheckBoxState();
543 this.toggleErrorTextAndSearchBox();
547 this.manageCheckBoxState();
551 this.toggleErrorTextAndSearchBox();
555 this.toggleErrorTextAndSearchBox();
559 if (!this.pictureVideoCheckbox.isSelected() && !this.documentsCheckbox.isSelected() && !this.allFileCategoriesRadioButton.isSelected()) {
560 this.searchButton.setEnabled(
false);
561 this.errorText.setVisible(
true);
563 this.searchButton.setEnabled(
true);
564 this.errorText.setVisible(
false);
569 selectDataSourceComboBox.setEnabled(selected);
570 if (selectDataSourceComboBox.isEnabled()) {
571 selectDataSourceComboBox.setSelectedIndex(0);
572 singleDataSource =
true;
578 if (this.allFileCategoriesRadioButton.isSelected()) {
580 this.pictureViewCheckboxState = this.pictureVideoCheckbox.isSelected();
581 this.documentsCheckboxState = this.documentsCheckbox.isSelected();
583 this.pictureVideoCheckbox.setEnabled(
false);
584 this.documentsCheckbox.setEnabled(
false);
587 if (this.selectedFileCategoriesButton.isSelected()) {
589 this.pictureVideoCheckbox.setSelected(this.pictureViewCheckboxState);
590 this.documentsCheckbox.setSelected(this.documentsCheckboxState);
592 this.pictureVideoCheckbox.setEnabled(
true);
593 this.documentsCheckbox.setEnabled(
true);
595 this.toggleErrorTextAndSearchBox();
void toggleErrorTextAndSearchBox()
javax.swing.JCheckBox pictureVideoCheckbox
void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JLabel dataSourceLabel
void searchButtonActionPerformed(java.awt.event.ActionEvent evt)
boolean pictureViewCheckboxState
void selectDataSourceComboBoxActionPerformed(java.awt.event.ActionEvent evt)
static Case getOpenCase()
void withinDataSourceRadioButtonActionPerformed(java.awt.event.ActionEvent evt)
String selectedDataSource
void allDataSourcesRadioButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JCheckBox documentsCheckbox
static DataResultTopComponent createInstance(String title, String description, Node node, int childNodeCount)
void withinDataSourceSelected(boolean selected)
javax.swing.ButtonGroup dataSourcesButtonGroup
javax.swing.JLabel categoriesLabel
javax.swing.JRadioButton allDataSourcesRadioButton
javax.swing.JRadioButton selectedFileCategoriesButton
javax.swing.ButtonGroup fileTypeFilterButtonGroup
javax.swing.JButton searchButton
SleuthkitCase getSleuthkitCase()
javax.swing.JLabel errorText
javax.swing.JButton cancelButton
void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt)
synchronized static Logger getLogger(String name)
void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt)
javax.swing.JRadioButton allFileCategoriesRadioButton
javax.swing.JRadioButton withinDataSourceRadioButton
boolean documentsCheckboxState
static final Long NO_DATA_SOURCE_SELECTED
void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt)
static void info(String message)
javax.swing.JLabel commonFilesSearchLabel
ComboBoxModel< String > dataSourcesList
void manageCheckBoxState()
javax.swing.JComboBox< String > selectDataSourceComboBox
void cancelButtonActionPerformed(java.awt.event.ActionEvent evt)
static void error(String message)
Map< Long, String > dataSourceMap