19 package org.sleuthkit.autopsy.contentviewers;
21 import java.awt.BorderLayout;
22 import java.awt.Component;
23 import java.awt.Cursor;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.LinkedHashMap;
32 import java.util.List;
34 import java.util.Objects;
35 import java.util.concurrent.ExecutionException;
36 import java.util.function.Consumer;
37 import java.util.logging.Level;
38 import javax.swing.JComboBox;
39 import javax.swing.JFileChooser;
40 import javax.swing.JOptionPane;
41 import javax.swing.SwingWorker;
42 import javax.swing.filechooser.FileNameExtensionFilter;
43 import org.apache.commons.io.FilenameUtils;
44 import org.openide.util.NbBundle;
45 import org.openide.windows.WindowManager;
57 @SuppressWarnings(
"PMD.SingularField")
58 class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
60 private static final long serialVersionUID = 1L;
61 public static final String[] SUPPORTED_MIMETYPES =
new String[]{
"application/x-sqlite3"};
62 private static final int ROWS_PER_PAGE = 100;
63 private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
64 private final SQLiteTableView selectedTableView =
new SQLiteTableView();
65 private AbstractFile sqliteDbFile;
67 private SQLiteTableReader viewReader;
69 private Map<String, Object> row =
new LinkedHashMap<>();
70 private List<Map<String, Object>> pageOfTableRows =
new ArrayList<>();
71 private List<String> currentTableHeader =
new ArrayList<>();
72 private String prevTableName;
75 private int currPage = 0;
77 SwingWorker<?, ?> worker;
79 private final JFileChooserFactory chooserHelper =
new JFileChooserFactory();
86 jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
94 @SuppressWarnings(
"unchecked")
96 private
void initComponents() {
98 jHdrPanel =
new javax.swing.JPanel();
99 tablesDropdownList =
new javax.swing.JComboBox<>();
100 jLabel1 =
new javax.swing.JLabel();
101 numEntriesField =
new javax.swing.JTextField();
102 jLabel2 =
new javax.swing.JLabel();
103 currPageLabel =
new javax.swing.JLabel();
104 jLabel3 =
new javax.swing.JLabel();
105 numPagesLabel =
new javax.swing.JLabel();
106 prevPageButton =
new javax.swing.JButton();
107 nextPageButton =
new javax.swing.JButton();
108 exportCsvButton =
new javax.swing.JButton();
109 jTableDataPanel =
new javax.swing.JPanel();
111 jHdrPanel.setPreferredSize(
new java.awt.Dimension(536, 40));
113 tablesDropdownList.setModel(
new javax.swing.DefaultComboBoxModel<>(
new String[] {
"Item 1",
"Item 2",
"Item 3",
"Item 4" }));
114 tablesDropdownList.addActionListener(
new java.awt.event.ActionListener() {
115 public void actionPerformed(java.awt.event.ActionEvent evt) {
116 tablesDropdownListActionPerformed(evt);
120 org.openide.awt.Mnemonics.setLocalizedText(jLabel1,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.jLabel1.text"));
122 numEntriesField.setEditable(
false);
123 numEntriesField.setText(
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.numEntriesField.text"));
124 numEntriesField.setBorder(null);
126 org.openide.awt.Mnemonics.setLocalizedText(jLabel2,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.jLabel2.text"));
128 org.openide.awt.Mnemonics.setLocalizedText(currPageLabel,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.currPageLabel.text"));
130 org.openide.awt.Mnemonics.setLocalizedText(jLabel3,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.jLabel3.text"));
132 org.openide.awt.Mnemonics.setLocalizedText(numPagesLabel,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.numPagesLabel.text"));
134 prevPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back.png")));
135 org.openide.awt.Mnemonics.setLocalizedText(prevPageButton,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.prevPageButton.text"));
136 prevPageButton.setBorderPainted(
false);
137 prevPageButton.setContentAreaFilled(
false);
138 prevPageButton.setDisabledSelectedIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_back_disabled.png")));
139 prevPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
140 prevPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
141 prevPageButton.addActionListener(
new java.awt.event.ActionListener() {
142 public void actionPerformed(java.awt.event.ActionEvent evt) {
143 prevPageButtonActionPerformed(evt);
147 nextPageButton.setIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward.png")));
148 org.openide.awt.Mnemonics.setLocalizedText(nextPageButton,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.nextPageButton.text"));
149 nextPageButton.setBorderPainted(
false);
150 nextPageButton.setContentAreaFilled(
false);
151 nextPageButton.setDisabledSelectedIcon(
new javax.swing.ImageIcon(getClass().getResource(
"/org/sleuthkit/autopsy/corecomponents/btn_step_forward_disabled.png")));
152 nextPageButton.setMargin(
new java.awt.Insets(2, 0, 2, 0));
153 nextPageButton.setPreferredSize(
new java.awt.Dimension(23, 23));
154 nextPageButton.addActionListener(
new java.awt.event.ActionListener() {
155 public void actionPerformed(java.awt.event.ActionEvent evt) {
156 nextPageButtonActionPerformed(evt);
160 org.openide.awt.Mnemonics.setLocalizedText(exportCsvButton,
org.openide.util.NbBundle.getMessage(SQLiteViewer.class,
"SQLiteViewer.exportCsvButton.text"));
161 exportCsvButton.addActionListener(
new java.awt.event.ActionListener() {
162 public void actionPerformed(java.awt.event.ActionEvent evt) {
163 exportCsvButtonActionPerformed(evt);
167 javax.swing.GroupLayout jHdrPanelLayout =
new javax.swing.GroupLayout(jHdrPanel);
168 jHdrPanel.setLayout(jHdrPanelLayout);
169 jHdrPanelLayout.setHorizontalGroup(
170 jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
171 .addGroup(jHdrPanelLayout.createSequentialGroup()
173 .addComponent(jLabel1)
174 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
175 .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
177 .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE)
179 .addComponent(jLabel2)
180 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
181 .addComponent(currPageLabel)
182 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
183 .addComponent(jLabel3)
184 .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
185 .addComponent(numPagesLabel)
187 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
189 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
191 .addComponent(exportCsvButton)
192 .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
194 jHdrPanelLayout.setVerticalGroup(
195 jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
196 .addGroup(jHdrPanelLayout.createSequentialGroup()
198 .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
199 .addComponent(exportCsvButton)
200 .addComponent(nextPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
201 .addComponent(prevPageButton, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
202 .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
203 .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
204 .addComponent(jLabel1)
205 .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
206 .addComponent(jLabel2)
207 .addComponent(currPageLabel)
208 .addComponent(jLabel3)
209 .addComponent(numPagesLabel)))
213 jTableDataPanel.setLayout(
new java.awt.BorderLayout());
215 javax.swing.GroupLayout layout =
new javax.swing.GroupLayout(
this);
216 this.setLayout(layout);
217 layout.setHorizontalGroup(
218 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
219 .addComponent(jHdrPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 569, Short.MAX_VALUE)
220 .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
222 layout.setVerticalGroup(
223 layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
224 .addGroup(layout.createSequentialGroup()
225 .addComponent(jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 53, javax.swing.GroupLayout.PREFERRED_SIZE)
227 .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE))
231 private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {
232 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
234 if (currPage * ROWS_PER_PAGE > numRows) {
235 nextPageButton.setEnabled(
false);
237 currPageLabel.setText(Integer.toString(currPage));
238 prevPageButton.setEnabled(
true);
241 String tableName = (String) this.tablesDropdownList.getSelectedItem();
242 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
243 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
246 private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {
248 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
251 prevPageButton.setEnabled(
false);
253 currPageLabel.setText(Integer.toString(currPage));
254 nextPageButton.setEnabled(
true);
257 String tableName = (String) this.tablesDropdownList.getSelectedItem();
258 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
259 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
262 private void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt) {
263 JComboBox<?> cb = (JComboBox<?>) evt.getSource();
264 String tableName = (String) cb.getSelectedItem();
265 if (null == tableName) {
268 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
269 selectTable(tableName);
270 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
280 @NbBundle.Messages({
"SQLiteViewer.csvExport.fileName.empty=Please input a file name for exporting.",
281 "SQLiteViewer.csvExport.title=Export to csv file",
282 "SQLiteViewer.csvExport.confirm.msg=Do you want to overwrite the existing file?"})
283 private void exportCsvButtonActionPerformed(java.awt.event.ActionEvent evt) {
284 Case openCase = Case.getCurrentCase();
285 File caseDirectory =
new File(openCase.getExportDirectory());
286 JFileChooser fileChooser = chooserHelper.getChooser();
287 fileChooser.setDragEnabled(
false);
288 fileChooser.setCurrentDirectory(caseDirectory);
290 FileNameExtensionFilter csvFilter =
new FileNameExtensionFilter(
"*.csv",
"csv");
291 fileChooser.addChoosableFileFilter(csvFilter);
292 fileChooser.setAcceptAllFileFilterUsed(
true);
293 fileChooser.setFileFilter(csvFilter);
294 fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
295 String defaultFileName = (String) this.tablesDropdownList.getSelectedItem();
296 fileChooser.setSelectedFile(
new File(defaultFileName));
297 int choice = fileChooser.showSaveDialog((Component) evt.getSource());
298 if (JFileChooser.APPROVE_OPTION == choice) {
299 File file = fileChooser.getSelectedFile();
300 if (file.exists() && FilenameUtils.getExtension(file.getName()).equalsIgnoreCase(
"csv")) {
301 if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(
this,
302 Bundle.SQLiteViewer_csvExport_confirm_msg(),
303 Bundle.SQLiteViewer_csvExport_title(),
304 JOptionPane.YES_NO_OPTION)) {
310 exportTableToCsv(file);
315 private javax.swing.JLabel currPageLabel;
316 private javax.swing.JButton exportCsvButton;
317 private javax.swing.JPanel jHdrPanel;
318 private javax.swing.JLabel jLabel1;
319 private javax.swing.JLabel jLabel2;
320 private javax.swing.JLabel jLabel3;
321 private javax.swing.JPanel jTableDataPanel;
322 private javax.swing.JButton nextPageButton;
323 private javax.swing.JTextField numEntriesField;
324 private javax.swing.JLabel numPagesLabel;
325 private javax.swing.JButton prevPageButton;
326 private javax.swing.JComboBox<String> tablesDropdownList;
330 public List<String> getSupportedMIMETypes() {
331 return Arrays.asList(SUPPORTED_MIMETYPES);
335 public void setFile(AbstractFile file) {
336 if (worker != null) {
346 processSQLiteFile(file);
350 public Component getComponent() {
355 public void resetComponent() {
356 tablesDropdownList.setEnabled(
true);
357 tablesDropdownList.removeAllItems();
358 numEntriesField.setText(
"");
360 if(viewReader != null) {
363 }
catch (SQLiteTableReaderException ex) {
367 row =
new LinkedHashMap<>();
368 pageOfTableRows =
new ArrayList<>();
369 currentTableHeader =
new ArrayList<>();
378 "SQLiteViewer.comboBox.noTableEntry=No tables found",
379 "SQLiteViewer.errorMessage.interrupted=The processing of the file was interrupted.",
380 "SQLiteViewer.errorMessage.noCurrentCase=The case has been closed.",
381 "SQLiteViewer.errorMessage.failedToExtractFile=The file could not be extracted from the data source.",
382 "SQLiteViewer.errorMessage.failedToQueryDatabase=The database tables in the file could not be read.",
383 "SQLiteViewer.errorMessage.failedToinitJDBCDriver=The JDBC driver for SQLite could not be loaded.",
384 "# {0} - exception message",
"SQLiteViewer.errorMessage.unexpectedError=An unexpected error occurred:\n{0).",})
385 private void processSQLiteFile(
final AbstractFile file) {
387 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
388 worker =
new SQLiteViewerWorker(file) {
395 WorkerResults results;
399 viewReader = results.getReader();
400 tablesDropdownList.removeAllItems();
401 Collection<String> dbTablesMap = results.getDbTablesMap();
402 if (dbTablesMap.isEmpty()) {
403 tablesDropdownList.addItem(Bundle.SQLiteViewer_comboBox_noTableEntry());
404 tablesDropdownList.setEnabled(
false);
406 dbTablesMap.forEach((tableName) -> {
407 tablesDropdownList.addItem(tableName);
411 WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
412 }
catch (InterruptedException | ExecutionException ex) {
413 logger.log(Level.SEVERE, String.format(
"Failed to display SQL Viewer for file (%d)", file.getId()), ex);
421 @NbBundle.Messages({
"# {0} - tableName",
422 "SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}"
424 private void selectTable(String tableName) {
426 numRows = viewReader.getRowCount(tableName);
427 numEntriesField.setText(numRows +
" entries");
430 currPageLabel.setText(Integer.toString(currPage));
431 numPagesLabel.setText(Integer.toString((numRows / ROWS_PER_PAGE) + 1));
433 prevPageButton.setEnabled(
false);
436 exportCsvButton.setEnabled(
true);
437 nextPageButton.setEnabled(((numRows > ROWS_PER_PAGE)));
438 readTable(tableName, (currPage - 1) * ROWS_PER_PAGE + 1, ROWS_PER_PAGE);
440 exportCsvButton.setEnabled(
false);
441 nextPageButton.setEnabled(
false);
443 currentTableHeader =
new ArrayList<>();
444 viewReader.read(tableName);
445 Map<String, Object> columnRow =
new LinkedHashMap<>();
446 for (
int i = 0; i < currentTableHeader.size(); i++) {
447 columnRow.put(currentTableHeader.get(i),
"");
449 selectedTableView.setupTable(Collections.singletonList(columnRow));
451 }
catch (SQLiteTableReaderException ex) {
452 logger.log(Level.WARNING, String.format(
"Failed to load table %s "
453 +
"from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(),
454 sqliteDbFile.getId()), ex.getMessage());
455 MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));
459 @NbBundle.Messages({
"# {0} - tableName",
460 "SQLiteViewer.readTable.errorText=Error getting rows for table: {0}"})
461 private void readTable(String tableName,
int startRow,
int numRowsToRead) {
466 if (!tableName.equals(prevTableName)) {
467 prevTableName = tableName;
469 currentTableHeader =
new ArrayList<>();
470 viewReader.read(tableName, numRowsToRead, startRow - 1);
471 selectedTableView.setupTable(pageOfTableRows);
472 pageOfTableRows =
new ArrayList<>();
473 }
catch (SQLiteTableReaderException ex) {
474 logger.log(Level.WARNING, String.format(
"Failed to read table %s from DB file '%s' "
475 +
"(objId=%d) starting at row [%d] and limit [%d]",
476 tableName, sqliteDbFile.getName(), sqliteDbFile.getId(),
477 startRow - 1, numRowsToRead), ex.getMessage());
478 MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_readTable_errorText(tableName));
488 private SQLiteTableReader initReader(AbstractFile sqliteFile) {
489 return new SQLiteTableReader.Builder(sqliteFile)
490 .forAllColumnNames((columnName) -> {
491 currentTableHeader.add(columnName);
493 .forAllTableValues(getForAllStrategy()).build();
508 private Consumer<Object> getForAllStrategy() {
509 return new Consumer<Object>() {
510 private int rowIndex = 0;
513 public void accept(Object t) {
515 String objectStr = (t instanceof byte[]) ?
"BLOB Data not shown"
516 : Objects.toString(t,
"");
518 row.put(currentTableHeader.get(rowIndex - 1), objectStr);
522 if (rowIndex == currentTableHeader.size()) {
523 pageOfTableRows.add(row);
524 row =
new LinkedHashMap<>();
526 rowIndex %= currentTableHeader.size();
532 private int totalColumnCount;
534 @NbBundle.Messages({
"SQLiteViewer.exportTableToCsv.write.errText=Failed to export table content to csv file.",
535 "SQLiteViewer.exportTableToCsv.FileName=File name: ",
536 "SQLiteViewer.exportTableToCsv.TableName=Table name: "
538 private void exportTableToCsv(File file) {
539 final File csvFile =
new File(file.toString() +
".csv");
540 final String tableName = (String) this.tablesDropdownList.getSelectedItem();
542 SwingWorker<String, Void> csvWorker =
new SwingWorker<String, Void>() {
544 protected String doInBackground() throws Exception {
545 try (FileOutputStream out =
new FileOutputStream(csvFile,
false)) {
546 try (SQLiteTableReader sqliteStream =
new SQLiteTableReader.Builder(sqliteDbFile)
547 .forAllColumnNames(getColumnNameCSVStrategy(out))
548 .forAllTableValues(getForAllCSVStrategy(out)).build()) {
549 totalColumnCount = sqliteStream.getColumnCount(tableName);
550 sqliteStream.read(tableName);
552 }
catch (IOException | SQLiteTableReaderException | RuntimeException ex) {
553 logger.log(Level.WARNING, String.format(
"Failed to export table [%s]"
554 +
" to CSV in sqlite file '%s' (objId=%d)", tableName, sqliteDbFile.getName(),
555 sqliteDbFile.getId()), ex.getMessage());
557 return Bundle.SQLiteViewer_exportTableToCsv_write_errText();
565 String message =
get();
566 if (!message.isEmpty()) {
567 MessageNotifyUtil.Message.error(message);
569 }
catch (InterruptedException | ExecutionException ex) {
570 logger.log(Level.SEVERE,
"Failure occurred writing sql csv file.", ex);
593 private Consumer<String> getColumnNameCSVStrategy(FileOutputStream out) {
594 return new Consumer<String>() {
595 private int columnIndex = 0;
598 public void accept(String columnName) {
600 String csvString = columnName;
602 if (columnIndex == 1) {
603 csvString =
"\"" + csvString +
"\"";
605 csvString =
",\"" + csvString +
"\"";
607 if (columnIndex == totalColumnCount) {
612 out.write(csvString.getBytes());
613 }
catch (IOException ex) {
619 throw new RuntimeException(ex);
639 private Consumer<Object> getForAllCSVStrategy(FileOutputStream out) {
640 return new Consumer<Object>() {
641 private int rowIndex = 0;
644 public void accept(Object tableValue) {
648 String objectStr = (tableValue instanceof byte[])
649 ?
"BLOB Data not shown" : Objects.toString(tableValue,
"");
650 objectStr =
"\"" + objectStr +
"\"";
653 objectStr =
"," + objectStr;
655 if (rowIndex == totalColumnCount) {
660 out.write(objectStr.getBytes());
661 }
catch (IOException ex) {
667 throw new RuntimeException(ex);
669 rowIndex %= totalColumnCount;
675 public boolean isSupported(AbstractFile file) {
685 private final AbstractFile
file;
710 this.reader = reader;
711 this.dbTablesMap = dbTablesMap;
718 Collection<String> getDbTablesMap() {
List< String > getTableNames()
final Collection< String > dbTablesMap
final SQLiteTableReader reader
WorkerResults doInBackground()