Autopsy  4.7.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AbstractSqlEamDb.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2018 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.centralrepository.datamodel;
20 
21 import java.net.UnknownHostException;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Collection;
25 import java.util.LinkedHashSet;
26 import java.util.stream.Collectors;
27 import java.sql.Connection;
28 import java.sql.PreparedStatement;
29 import java.sql.ResultSet;
30 import java.sql.SQLException;
31 import java.sql.Statement;
32 import java.sql.Types;
33 import java.time.LocalDate;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.logging.Level;
39 import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
43 import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
44 import org.sleuthkit.datamodel.TskData;
45 
51 abstract class AbstractSqlEamDb implements EamDb {
52 
53  private final static Logger logger = Logger.getLogger(AbstractSqlEamDb.class.getName());
54 
55  protected final List<CorrelationAttribute.Type> defaultCorrelationTypes;
56 
57  private int bulkArtifactsCount;
58  protected int bulkArtifactsThreshold;
59  private final Map<String, Collection<CorrelationAttribute>> bulkArtifacts;
60 
61  // number of instances to keep in bulk queue before doing an insert.
62  // Update Test code if this changes. It's hard coded there.
63  static final int DEFAULT_BULK_THRESHHOLD = 1000;
64 
70  protected AbstractSqlEamDb() throws EamDbException {
71  bulkArtifactsCount = 0;
72  bulkArtifacts = new HashMap<>();
73 
74  defaultCorrelationTypes = CorrelationAttribute.getDefaultCorrelationTypes();
75  defaultCorrelationTypes.forEach((type) -> {
76  bulkArtifacts.put(type.getDbTableName(), new ArrayList<>());
77  });
78  }
79 
83  protected abstract Connection connect() throws EamDbException;
84 
93  @Override
94  public void newDbInfo(String name, String value) throws EamDbException {
95  Connection conn = connect();
96 
97  PreparedStatement preparedStatement = null;
98  String sql = "INSERT INTO db_info (name, value) VALUES (?, ?) "
99  + getConflictClause();
100  try {
101  preparedStatement = conn.prepareStatement(sql);
102  preparedStatement.setString(1, name);
103  preparedStatement.setString(2, value);
104  preparedStatement.executeUpdate();
105  } catch (SQLException ex) {
106  throw new EamDbException("Error adding new name/value pair to db_info.", ex);
107  } finally {
108  EamDbUtil.closeStatement(preparedStatement);
110  }
111 
112  }
113 
123  @Override
124  public String getDbInfo(String name) throws EamDbException {
125  Connection conn = connect();
126 
127  PreparedStatement preparedStatement = null;
128  ResultSet resultSet = null;
129  String value = null;
130  String sql = "SELECT value FROM db_info WHERE name=?";
131  try {
132  preparedStatement = conn.prepareStatement(sql);
133  preparedStatement.setString(1, name);
134  resultSet = preparedStatement.executeQuery();
135  if (resultSet.next()) {
136  value = resultSet.getString("value");
137  }
138  } catch (SQLException ex) {
139  throw new EamDbException("Error getting value for name.", ex);
140  } finally {
141  EamDbUtil.closeStatement(preparedStatement);
142  EamDbUtil.closeResultSet(resultSet);
144  }
145 
146  return value;
147  }
148 
157  @Override
158  public void updateDbInfo(String name, String value) throws EamDbException {
159  Connection conn = connect();
160 
161  PreparedStatement preparedStatement = null;
162  String sql = "UPDATE db_info SET value=? WHERE name=?";
163  try {
164  preparedStatement = conn.prepareStatement(sql);
165  preparedStatement.setString(1, value);
166  preparedStatement.setString(2, name);
167  preparedStatement.executeUpdate();
168  } catch (SQLException ex) {
169  throw new EamDbException("Error updating value for name.", ex);
170  } finally {
171  EamDbUtil.closeStatement(preparedStatement);
173  }
174  }
175 
185  @Override
186  public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
187 
188  // check if there is already an existing CorrelationCase for this Case
189  CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
190  if (cRCase != null) {
191  return cRCase;
192  }
193 
194  Connection conn = connect();
195  PreparedStatement preparedStatement = null;
196 
197  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
198  + "examiner_name, examiner_email, examiner_phone, notes) "
199  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
200  + getConflictClause();
201 
202  try {
203  preparedStatement = conn.prepareStatement(sql);
204 
205  preparedStatement.setString(1, eamCase.getCaseUUID());
206  if (null == eamCase.getOrg()) {
207  preparedStatement.setNull(2, Types.INTEGER);
208  } else {
209  preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
210  }
211  preparedStatement.setString(3, eamCase.getDisplayName());
212  preparedStatement.setString(4, eamCase.getCreationDate());
213  if ("".equals(eamCase.getCaseNumber())) {
214  preparedStatement.setNull(5, Types.INTEGER);
215  } else {
216  preparedStatement.setString(5, eamCase.getCaseNumber());
217  }
218  if ("".equals(eamCase.getExaminerName())) {
219  preparedStatement.setNull(6, Types.INTEGER);
220  } else {
221  preparedStatement.setString(6, eamCase.getExaminerName());
222  }
223  if ("".equals(eamCase.getExaminerEmail())) {
224  preparedStatement.setNull(7, Types.INTEGER);
225  } else {
226  preparedStatement.setString(7, eamCase.getExaminerEmail());
227  }
228  if ("".equals(eamCase.getExaminerPhone())) {
229  preparedStatement.setNull(8, Types.INTEGER);
230  } else {
231  preparedStatement.setString(8, eamCase.getExaminerPhone());
232  }
233  if ("".equals(eamCase.getNotes())) {
234  preparedStatement.setNull(9, Types.INTEGER);
235  } else {
236  preparedStatement.setString(9, eamCase.getNotes());
237  }
238 
239  preparedStatement.executeUpdate();
240  } catch (SQLException ex) {
241  throw new EamDbException("Error inserting new case.", ex); // NON-NLS
242  } finally {
243  EamDbUtil.closeStatement(preparedStatement);
245  }
246 
247  // get a new version with the updated ID
248  return getCaseByUUID(eamCase.getCaseUUID());
249  }
250 
256  @Override
257  public CorrelationCase newCase(Case autopsyCase) throws EamDbException {
258  if (autopsyCase == null) {
259  throw new EamDbException("Case is null");
260  }
261 
262  CorrelationCase curCeCase = new CorrelationCase(
263  -1,
264  autopsyCase.getName(), // unique case ID
266  autopsyCase.getDisplayName(),
267  autopsyCase.getCreatedDate(),
268  autopsyCase.getNumber(),
269  autopsyCase.getExaminer(),
270  autopsyCase.getExaminerEmail(),
271  autopsyCase.getExaminerPhone(),
272  autopsyCase.getCaseNotes());
273  return newCase(curCeCase);
274  }
275 
276  @Override
277  public CorrelationCase getCase(Case autopsyCase) throws EamDbException {
278  return getCaseByUUID(autopsyCase.getName());
279  }
280 
286  @Override
287  public void updateCase(CorrelationCase eamCase) throws EamDbException {
288  if (eamCase == null) {
289  throw new EamDbException("Correlation case is null");
290  }
291 
292  Connection conn = connect();
293 
294  PreparedStatement preparedStatement = null;
295  String sql = "UPDATE cases "
296  + "SET org_id=?, case_name=?, creation_date=?, case_number=?, examiner_name=?, examiner_email=?, examiner_phone=?, notes=? "
297  + "WHERE case_uid=?";
298 
299  try {
300  preparedStatement = conn.prepareStatement(sql);
301 
302  if (null == eamCase.getOrg()) {
303  preparedStatement.setNull(1, Types.INTEGER);
304  } else {
305  preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
306  }
307  preparedStatement.setString(2, eamCase.getDisplayName());
308  preparedStatement.setString(3, eamCase.getCreationDate());
309 
310  if ("".equals(eamCase.getCaseNumber())) {
311  preparedStatement.setNull(4, Types.INTEGER);
312  } else {
313  preparedStatement.setString(4, eamCase.getCaseNumber());
314  }
315  if ("".equals(eamCase.getExaminerName())) {
316  preparedStatement.setNull(5, Types.INTEGER);
317  } else {
318  preparedStatement.setString(5, eamCase.getExaminerName());
319  }
320  if ("".equals(eamCase.getExaminerEmail())) {
321  preparedStatement.setNull(6, Types.INTEGER);
322  } else {
323  preparedStatement.setString(6, eamCase.getExaminerEmail());
324  }
325  if ("".equals(eamCase.getExaminerPhone())) {
326  preparedStatement.setNull(7, Types.INTEGER);
327  } else {
328  preparedStatement.setString(7, eamCase.getExaminerPhone());
329  }
330  if ("".equals(eamCase.getNotes())) {
331  preparedStatement.setNull(8, Types.INTEGER);
332  } else {
333  preparedStatement.setString(8, eamCase.getNotes());
334  }
335 
336  preparedStatement.setString(9, eamCase.getCaseUUID());
337 
338  preparedStatement.executeUpdate();
339  } catch (SQLException ex) {
340  throw new EamDbException("Error updating case.", ex); // NON-NLS
341  } finally {
342  EamDbUtil.closeStatement(preparedStatement);
344  }
345  }
346 
354  @Override
355  public CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException {
356  // @@@ We should have a cache here...
357 
358  Connection conn = connect();
359 
360  CorrelationCase eamCaseResult = null;
361  PreparedStatement preparedStatement = null;
362  ResultSet resultSet = null;
363 
364  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
365  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
366  + "FROM cases "
367  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
368  + "WHERE case_uid=?";
369 
370  try {
371  preparedStatement = conn.prepareStatement(sql);
372  preparedStatement.setString(1, caseUUID);
373  resultSet = preparedStatement.executeQuery();
374  if (resultSet.next()) {
375  eamCaseResult = getEamCaseFromResultSet(resultSet);
376  }
377  } catch (SQLException ex) {
378  throw new EamDbException("Error getting case details.", ex); // NON-NLS
379  } finally {
380  EamDbUtil.closeStatement(preparedStatement);
381  EamDbUtil.closeResultSet(resultSet);
383  }
384 
385  return eamCaseResult;
386  }
387 
393  @Override
394  public List<CorrelationCase> getCases() throws EamDbException {
395  Connection conn = connect();
396 
397  List<CorrelationCase> cases = new ArrayList<>();
398  CorrelationCase eamCaseResult;
399  PreparedStatement preparedStatement = null;
400  ResultSet resultSet = null;
401 
402  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
403  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
404  + "FROM cases "
405  + "LEFT JOIN organizations ON cases.org_id=organizations.id";
406 
407  try {
408  preparedStatement = conn.prepareStatement(sql);
409  resultSet = preparedStatement.executeQuery();
410  while (resultSet.next()) {
411  eamCaseResult = getEamCaseFromResultSet(resultSet);
412  cases.add(eamCaseResult);
413  }
414  } catch (SQLException ex) {
415  throw new EamDbException("Error getting all cases.", ex); // NON-NLS
416  } finally {
417  EamDbUtil.closeStatement(preparedStatement);
418  EamDbUtil.closeResultSet(resultSet);
420  }
421 
422  return cases;
423  }
424 
430  @Override
431  public void newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
432  if (eamDataSource.getCaseID() == -1) {
433  throw new EamDbException("Case ID is -1");
434  } else if (eamDataSource.getID() != -1) {
435  throw new EamDbException("Database ID is already set in object");
436  }
437  Connection conn = connect();
438 
439  PreparedStatement preparedStatement = null;
440 
441  String sql = "INSERT INTO data_sources(device_id, case_id, name) VALUES (?, ?, ?) "
442  + getConflictClause();
443 
444  try {
445  preparedStatement = conn.prepareStatement(sql);
446 
447  preparedStatement.setString(1, eamDataSource.getDeviceID());
448  preparedStatement.setInt(2, eamDataSource.getCaseID());
449  preparedStatement.setString(3, eamDataSource.getName());
450 
451  preparedStatement.executeUpdate();
452  } catch (SQLException ex) {
453  throw new EamDbException("Error inserting new data source.", ex); // NON-NLS
454  } finally {
455  EamDbUtil.closeStatement(preparedStatement);
457  }
458  }
459 
469  @Override
470  public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
471  if (correlationCase == null) {
472  throw new EamDbException("Correlation case is null");
473  }
474 
475  Connection conn = connect();
476 
477  CorrelationDataSource eamDataSourceResult = null;
478  PreparedStatement preparedStatement = null;
479  ResultSet resultSet = null;
480 
481  String sql = "SELECT * FROM data_sources WHERE device_id=? AND case_id=?"; // NON-NLS
482 
483  try {
484  preparedStatement = conn.prepareStatement(sql);
485  preparedStatement.setString(1, dataSourceDeviceId);
486  preparedStatement.setInt(2, correlationCase.getID());
487  resultSet = preparedStatement.executeQuery();
488  if (resultSet.next()) {
489  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
490  }
491  } catch (SQLException ex) {
492  throw new EamDbException("Error getting data source.", ex); // NON-NLS
493  } finally {
494  EamDbUtil.closeStatement(preparedStatement);
495  EamDbUtil.closeResultSet(resultSet);
497  }
498 
499  return eamDataSourceResult;
500  }
501 
507  @Override
508  public List<CorrelationDataSource> getDataSources() throws EamDbException {
509  Connection conn = connect();
510 
511  List<CorrelationDataSource> dataSources = new ArrayList<>();
512  CorrelationDataSource eamDataSourceResult;
513  PreparedStatement preparedStatement = null;
514  ResultSet resultSet = null;
515 
516  String sql = "SELECT * FROM data_sources";
517 
518  try {
519  preparedStatement = conn.prepareStatement(sql);
520  resultSet = preparedStatement.executeQuery();
521  while (resultSet.next()) {
522  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
523  dataSources.add(eamDataSourceResult);
524  }
525  } catch (SQLException ex) {
526  throw new EamDbException("Error getting all data sources.", ex); // NON-NLS
527  } finally {
528  EamDbUtil.closeStatement(preparedStatement);
529  EamDbUtil.closeResultSet(resultSet);
531  }
532 
533  return dataSources;
534  }
535 
542  @Override
543  public void addArtifact(CorrelationAttribute eamArtifact) throws EamDbException {
544  if (eamArtifact == null) {
545  throw new EamDbException("CorrelationAttribute is null");
546  }
547  if (eamArtifact.getCorrelationType() == null) {
548  throw new EamDbException("Correlation type is null");
549  }
550  if (eamArtifact.getCorrelationValue() == null) {
551  throw new EamDbException("Correlation value is null");
552  }
553 
554  Connection conn = connect();
555 
556  List<CorrelationAttributeInstance> eamInstances = eamArtifact.getInstances();
557  PreparedStatement preparedStatement = null;
558 
559  // @@@ We should cache the case and data source IDs in memory
560  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
561  String sql
562  = "INSERT INTO "
563  + tableName
564  + "(case_id, data_source_id, value, file_path, known_status, comment) "
565  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
566  + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
567  + getConflictClause();
568 
569  try {
570  preparedStatement = conn.prepareStatement(sql);
571  for (CorrelationAttributeInstance eamInstance : eamInstances) {
572  if (!eamArtifact.getCorrelationValue().isEmpty()) {
573  if (eamInstance.getCorrelationCase() == null) {
574  throw new EamDbException("CorrelationAttributeInstance case is null");
575  }
576  if (eamInstance.getCorrelationDataSource() == null) {
577  throw new EamDbException("CorrelationAttributeInstance data source is null");
578  }
579  if (eamInstance.getKnownStatus() == null) {
580  throw new EamDbException("CorrelationAttributeInstance known status is null");
581  }
582 
583  preparedStatement.setString(1, eamInstance.getCorrelationCase().getCaseUUID());
584  preparedStatement.setString(2, eamInstance.getCorrelationDataSource().getDeviceID());
585  preparedStatement.setInt(3, eamInstance.getCorrelationDataSource().getCaseID());
586  preparedStatement.setString(4, eamArtifact.getCorrelationValue());
587  preparedStatement.setString(5, eamInstance.getFilePath());
588  preparedStatement.setByte(6, eamInstance.getKnownStatus().getFileKnownValue());
589  if ("".equals(eamInstance.getComment())) {
590  preparedStatement.setNull(7, Types.INTEGER);
591  } else {
592  preparedStatement.setString(7, eamInstance.getComment());
593  }
594 
595  preparedStatement.executeUpdate();
596  }
597  }
598  } catch (SQLException ex) {
599  throw new EamDbException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
600  } finally {
601  EamDbUtil.closeStatement(preparedStatement);
603  }
604  }
605 
617  @Override
618  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException {
619  if (aType == null) {
620  throw new EamDbException("Correlation type is null");
621  }
622  Connection conn = connect();
623 
624  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
625 
626  CorrelationAttributeInstance artifactInstance;
627  PreparedStatement preparedStatement = null;
628  ResultSet resultSet = null;
629 
630  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
631  String sql
632  = "SELECT "
633  + tableName
634  + ".id, cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
635  + tableName
636  + " LEFT JOIN cases ON "
637  + tableName
638  + ".case_id=cases.id"
639  + " LEFT JOIN data_sources ON "
640  + tableName
641  + ".data_source_id=data_sources.id"
642  + " WHERE value=?";
643 
644  try {
645  preparedStatement = conn.prepareStatement(sql);
646  preparedStatement.setString(1, value);
647  resultSet = preparedStatement.executeQuery();
648  while (resultSet.next()) {
649  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet);
650  artifactInstances.add(artifactInstance);
651  }
652  } catch (SQLException ex) {
653  throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
654  } finally {
655  EamDbUtil.closeStatement(preparedStatement);
656  EamDbUtil.closeResultSet(resultSet);
658  }
659 
660  return artifactInstances;
661  }
662 
674  @Override
675  public List<CorrelationAttributeInstance> getArtifactInstancesByPath(CorrelationAttribute.Type aType, String filePath) throws EamDbException {
676  if (aType == null) {
677  throw new EamDbException("Correlation type is null");
678  }
679  if (filePath == null) {
680  throw new EamDbException("Correlation value is null");
681  }
682  Connection conn = connect();
683 
684  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
685 
686  CorrelationAttributeInstance artifactInstance;
687  PreparedStatement preparedStatement = null;
688  ResultSet resultSet = null;
689 
690  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
691  String sql
692  = "SELECT "
693  + tableName
694  + ".id, cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
695  + tableName
696  + " LEFT JOIN cases ON "
697  + tableName
698  + ".case_id=cases.id"
699  + " LEFT JOIN data_sources ON "
700  + tableName
701  + ".data_source_id=data_sources.id"
702  + " WHERE file_path=?";
703 
704  try {
705  preparedStatement = conn.prepareStatement(sql);
706  preparedStatement.setString(1, filePath.toLowerCase());
707  resultSet = preparedStatement.executeQuery();
708  while (resultSet.next()) {
709  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet);
710  artifactInstances.add(artifactInstance);
711  }
712  } catch (SQLException ex) {
713  throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
714  } finally {
715  EamDbUtil.closeStatement(preparedStatement);
716  EamDbUtil.closeResultSet(resultSet);
718  }
719 
720  return artifactInstances;
721  }
722 
733  @Override
734  public Long getCountArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException {
735  if (aType == null) {
736  throw new EamDbException("Correlation type is null");
737  }
738  if (value == null) {
739  throw new EamDbException("Correlation value is null");
740  }
741 
742  Connection conn = connect();
743 
744  Long instanceCount = 0L;
745  PreparedStatement preparedStatement = null;
746  ResultSet resultSet = null;
747 
748  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
749  String sql
750  = "SELECT count(*) FROM "
751  + tableName
752  + " WHERE value=?";
753 
754  try {
755  preparedStatement = conn.prepareStatement(sql);
756  preparedStatement.setString(1, value.toLowerCase());
757  resultSet = preparedStatement.executeQuery();
758  resultSet.next();
759  instanceCount = resultSet.getLong(1);
760  } catch (SQLException ex) {
761  throw new EamDbException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
762  } finally {
763  EamDbUtil.closeStatement(preparedStatement);
764  EamDbUtil.closeResultSet(resultSet);
766  }
767 
768  return instanceCount;
769  }
770 
771  @Override
772  public int getFrequencyPercentage(CorrelationAttribute corAttr) throws EamDbException {
773  if (corAttr == null) {
774  throw new EamDbException("CorrelationAttribute is null");
775  }
776  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
777  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
778  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
779  return commonalityPercentage.intValue();
780  }
781 
792  @Override
793  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException {
794  if (aType == null) {
795  throw new EamDbException("Correlation type is null");
796  }
797 
798  Connection conn = connect();
799 
800  Long instanceCount = 0L;
801  PreparedStatement preparedStatement = null;
802  ResultSet resultSet = null;
803 
804  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
805  String sql
806  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
807  + tableName
808  + " WHERE value=?) AS "
809  + tableName
810  + "_distinct_case_data_source_tuple";
811 
812  try {
813  preparedStatement = conn.prepareStatement(sql);
814  preparedStatement.setString(1, value);
815  resultSet = preparedStatement.executeQuery();
816  resultSet.next();
817  instanceCount = resultSet.getLong(1);
818  } catch (SQLException ex) {
819  throw new EamDbException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
820  } finally {
821  EamDbUtil.closeStatement(preparedStatement);
822  EamDbUtil.closeResultSet(resultSet);
824  }
825 
826  return instanceCount;
827  }
828 
829  @Override
830  public Long getCountUniqueDataSources() throws EamDbException {
831  Connection conn = connect();
832 
833  Long instanceCount = 0L;
834  PreparedStatement preparedStatement = null;
835  ResultSet resultSet = null;
836 
837  String stmt = "SELECT count(*) FROM data_sources";
838 
839  try {
840  preparedStatement = conn.prepareStatement(stmt);
841  resultSet = preparedStatement.executeQuery();
842  resultSet.next();
843  instanceCount = resultSet.getLong(1);
844  } catch (SQLException ex) {
845  throw new EamDbException("Error counting data sources.", ex); // NON-NLS
846  } finally {
847  EamDbUtil.closeStatement(preparedStatement);
848  EamDbUtil.closeResultSet(resultSet);
850  }
851 
852  return instanceCount;
853  }
854 
866  @Override
867  public Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException {
868  Connection conn = connect();
869 
870  Long instanceCount = 0L;
871  List<CorrelationAttribute.Type> artifactTypes = getDefinedCorrelationTypes();
872  PreparedStatement preparedStatement = null;
873  ResultSet resultSet = null;
874 
875  // Figure out sql variables or subqueries
876  String sql = "SELECT 0 ";
877 
878  for (CorrelationAttribute.Type type : artifactTypes) {
879  String table_name = EamDbUtil.correlationTypeToInstanceTableName(type);
880 
881  sql
882  += "+ (SELECT count(*) FROM "
883  + table_name
884  + " WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) and data_source_id=(SELECT id FROM data_sources WHERE device_id=?))";
885  }
886 
887  try {
888  preparedStatement = conn.prepareStatement(sql);
889 
890  for (int i = 0; i < artifactTypes.size(); ++i) {
891  preparedStatement.setString(2 * i + 1, caseUUID);
892  preparedStatement.setString(2 * i + 2, dataSourceID);
893  }
894 
895  resultSet = preparedStatement.executeQuery();
896  resultSet.next();
897  instanceCount = resultSet.getLong(1);
898  } catch (SQLException ex) {
899  throw new EamDbException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
900  } finally {
901  EamDbUtil.closeStatement(preparedStatement);
902  EamDbUtil.closeResultSet(resultSet);
904  }
905 
906  return instanceCount;
907  }
908 
916  @Override
917  public void prepareBulkArtifact(CorrelationAttribute eamArtifact) throws EamDbException {
918 
919  if (eamArtifact.getCorrelationType() == null) {
920  throw new EamDbException("Correlation type is null");
921  }
922 
923  synchronized (bulkArtifacts) {
924  bulkArtifacts.get(eamArtifact.getCorrelationType().getDbTableName()).add(eamArtifact);
925  bulkArtifactsCount++;
926 
927  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
928  bulkInsertArtifacts();
929  }
930  }
931  }
932 
938  protected abstract String getConflictClause();
939 
944  @Override
945  public void bulkInsertArtifacts() throws EamDbException {
946  List<CorrelationAttribute.Type> artifactTypes = getDefinedCorrelationTypes();
947 
948  Connection conn = connect();
949  PreparedStatement bulkPs = null;
950 
951  try {
952  synchronized (bulkArtifacts) {
953  if (bulkArtifactsCount == 0) {
954  return;
955  }
956 
957  for (CorrelationAttribute.Type type : artifactTypes) {
958 
959  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
960  String sql
961  = "INSERT INTO "
962  + tableName
963  + " (case_id, data_source_id, value, file_path, known_status, comment) "
964  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
965  + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
966  + getConflictClause();
967 
968  bulkPs = conn.prepareStatement(sql);
969 
970  Collection<CorrelationAttribute> eamArtifacts = bulkArtifacts.get(type.getDbTableName());
971  for (CorrelationAttribute eamArtifact : eamArtifacts) {
972  List<CorrelationAttributeInstance> eamInstances = eamArtifact.getInstances();
973 
974  for (CorrelationAttributeInstance eamInstance : eamInstances) {
975  if (!eamArtifact.getCorrelationValue().isEmpty()) {
976 
977  if (eamInstance.getCorrelationCase() == null) {
978  throw new EamDbException("CorrelationAttributeInstance case is null");
979  }
980  if (eamInstance.getCorrelationDataSource() == null) {
981  throw new EamDbException("CorrelationAttributeInstance data source is null");
982  }
983  if (eamInstance.getKnownStatus() == null) {
984  throw new EamDbException("CorrelationAttributeInstance known status is null");
985  }
986 
987  bulkPs.setString(1, eamInstance.getCorrelationCase().getCaseUUID());
988  bulkPs.setString(2, eamInstance.getCorrelationDataSource().getDeviceID());
989  bulkPs.setInt(3, eamInstance.getCorrelationDataSource().getCaseID());
990  bulkPs.setString(4, eamArtifact.getCorrelationValue());
991  bulkPs.setString(5, eamInstance.getFilePath());
992  bulkPs.setByte(6, eamInstance.getKnownStatus().getFileKnownValue());
993  if ("".equals(eamInstance.getComment())) {
994  bulkPs.setNull(7, Types.INTEGER);
995  } else {
996  bulkPs.setString(7, eamInstance.getComment());
997  }
998  bulkPs.addBatch();
999  }
1000  }
1001  }
1002 
1003  bulkPs.executeBatch();
1004  bulkArtifacts.get(type.getDbTableName()).clear();
1005  }
1006 
1007  TimingMetric timingMetric = EnterpriseHealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
1009 
1010  // Reset state
1011  bulkArtifactsCount = 0;
1012  }
1013  } catch (SQLException ex) {
1014  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
1015  } finally {
1016  EamDbUtil.closeStatement(bulkPs);
1017  EamDbUtil.closeConnection(conn);
1018  }
1019  }
1020 
1024  @Override
1025  public void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException {
1026  if (cases == null) {
1027  throw new EamDbException("cases argument is null");
1028  }
1029 
1030  if (cases.isEmpty()) {
1031  return;
1032  }
1033 
1034  Connection conn = connect();
1035 
1036  int counter = 0;
1037  PreparedStatement bulkPs = null;
1038  try {
1039  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1040  + "examiner_name, examiner_email, examiner_phone, notes) "
1041  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1042  + getConflictClause();
1043  bulkPs = conn.prepareStatement(sql);
1044 
1045  for (CorrelationCase eamCase : cases) {
1046  bulkPs.setString(1, eamCase.getCaseUUID());
1047  if (null == eamCase.getOrg()) {
1048  bulkPs.setNull(2, Types.INTEGER);
1049  } else {
1050  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1051  }
1052  bulkPs.setString(3, eamCase.getDisplayName());
1053  bulkPs.setString(4, eamCase.getCreationDate());
1054 
1055  if ("".equals(eamCase.getCaseNumber())) {
1056  bulkPs.setNull(5, Types.INTEGER);
1057  } else {
1058  bulkPs.setString(5, eamCase.getCaseNumber());
1059  }
1060  if ("".equals(eamCase.getExaminerName())) {
1061  bulkPs.setNull(6, Types.INTEGER);
1062  } else {
1063  bulkPs.setString(6, eamCase.getExaminerName());
1064  }
1065  if ("".equals(eamCase.getExaminerEmail())) {
1066  bulkPs.setNull(7, Types.INTEGER);
1067  } else {
1068  bulkPs.setString(7, eamCase.getExaminerEmail());
1069  }
1070  if ("".equals(eamCase.getExaminerPhone())) {
1071  bulkPs.setNull(8, Types.INTEGER);
1072  } else {
1073  bulkPs.setString(8, eamCase.getExaminerPhone());
1074  }
1075  if ("".equals(eamCase.getNotes())) {
1076  bulkPs.setNull(9, Types.INTEGER);
1077  } else {
1078  bulkPs.setString(9, eamCase.getNotes());
1079  }
1080 
1081  bulkPs.addBatch();
1082 
1083  counter++;
1084 
1085  // limit a batch's max size to bulkArtifactsThreshold
1086  if (counter >= bulkArtifactsThreshold) {
1087  bulkPs.executeBatch();
1088  counter = 0;
1089  }
1090  }
1091  // send the remaining batch records
1092  bulkPs.executeBatch();
1093  } catch (SQLException ex) {
1094  throw new EamDbException("Error inserting bulk cases.", ex); // NON-NLS
1095  } finally {
1096  EamDbUtil.closeStatement(bulkPs);
1097  EamDbUtil.closeConnection(conn);
1098  }
1099  }
1100 
1110  @Override
1111  public void updateAttributeInstanceComment(CorrelationAttribute eamArtifact) throws EamDbException {
1112  if (eamArtifact == null) {
1113  throw new EamDbException("CorrelationAttribute is null");
1114  }
1115 
1116  CorrelationAttributeInstance eamInstance = eamArtifact.getInstances().get(0);
1117 
1118  if (eamInstance == null) {
1119  throw new EamDbException("CorrelationAttributeInstance is null");
1120  }
1121  if (eamInstance.getCorrelationCase() == null) {
1122  throw new EamDbException("Correlation case is null");
1123  }
1124  if (eamInstance.getCorrelationDataSource() == null) {
1125  throw new EamDbException("Correlation data source is null");
1126  }
1127 
1128  Connection conn = connect();
1129  PreparedStatement preparedQuery = null;
1130  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1131 
1132  String sqlUpdate
1133  = "UPDATE "
1134  + tableName
1135  + " SET comment=? "
1136  + "WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) "
1137  + "AND data_source_id=(SELECT id FROM data_sources WHERE device_id=?) "
1138  + "AND value=? "
1139  + "AND file_path=?";
1140 
1141  try {
1142  preparedQuery = conn.prepareStatement(sqlUpdate);
1143  preparedQuery.setString(1, eamInstance.getComment());
1144  preparedQuery.setString(2, eamInstance.getCorrelationCase().getCaseUUID());
1145  preparedQuery.setString(3, eamInstance.getCorrelationDataSource().getDeviceID());
1146  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1147  preparedQuery.setString(5, eamInstance.getFilePath());
1148  preparedQuery.executeUpdate();
1149  } catch (SQLException ex) {
1150  throw new EamDbException("Error getting/setting artifact instance comment=" + eamInstance.getComment(), ex); // NON-NLS
1151  } finally {
1152  EamDbUtil.closeStatement(preparedQuery);
1153  EamDbUtil.closeConnection(conn);
1154  }
1155  }
1156 
1171  @Override
1172  public CorrelationAttribute getCorrelationAttribute(CorrelationAttribute.Type type, CorrelationCase correlationCase,
1173  CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException {
1174 
1175  if (type == null) {
1176  throw new EamDbException("Correlation type is null");
1177  }
1178  if (correlationCase == null) {
1179  throw new EamDbException("Correlation case is null");
1180  }
1181  if (correlationDataSource == null) {
1182  throw new EamDbException("Correlation data source is null");
1183  }
1184  if (value == null) {
1185  throw new EamDbException("Correlation value is null");
1186  }
1187  if (filePath == null) {
1188  throw new EamDbException("Correlation file path is null");
1189  }
1190 
1191  Connection conn = connect();
1192 
1193  PreparedStatement preparedStatement = null;
1194  ResultSet resultSet = null;
1195  CorrelationAttribute correlationAttribute = null;
1196 
1197  try {
1198  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1199  String sql
1200  = "SELECT id, known_status, comment FROM "
1201  + tableName
1202  + " WHERE case_id=?"
1203  + " AND data_source_id=?"
1204  + " AND value=?"
1205  + " AND file_path=?";
1206 
1207  preparedStatement = conn.prepareStatement(sql);
1208  preparedStatement.setInt(1, correlationCase.getID());
1209  preparedStatement.setInt(2, correlationDataSource.getID());
1210  preparedStatement.setString(3, value.toLowerCase());
1211  preparedStatement.setString(4, filePath.toLowerCase());
1212  resultSet = preparedStatement.executeQuery();
1213  if (resultSet.next()) {
1214  int instanceId = resultSet.getInt(1);
1215  int knownStatus = resultSet.getInt(2);
1216  String comment = resultSet.getString(3);
1217 
1218  correlationAttribute = new CorrelationAttribute(type, value);
1220  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus));
1221  correlationAttribute.addInstance(artifactInstance);
1222  }
1223  } catch (SQLException ex) {
1224  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1225  } finally {
1226  EamDbUtil.closeStatement(preparedStatement);
1227  EamDbUtil.closeResultSet(resultSet);
1228  EamDbUtil.closeConnection(conn);
1229  }
1230 
1231  return correlationAttribute;
1232  }
1233 
1244  @Override
1245  public void setArtifactInstanceKnownStatus(CorrelationAttribute eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
1246  if (eamArtifact == null) {
1247  throw new EamDbException("CorrelationAttribute is null");
1248  }
1249  if (knownStatus == null) {
1250  throw new EamDbException("Known status is null");
1251  }
1252  if (1 != eamArtifact.getInstances().size()) {
1253  throw new EamDbException("Error: Artifact must have exactly one (1) Artifact Instance to set as notable."); // NON-NLS
1254  }
1255 
1256  List<CorrelationAttributeInstance> eamInstances = eamArtifact.getInstances();
1257  CorrelationAttributeInstance eamInstance = eamInstances.get(0);
1258 
1259  if (eamInstance.getCorrelationCase() == null) {
1260  throw new EamDbException("Correlation case is null");
1261  }
1262  if (eamInstance.getCorrelationDataSource() == null) {
1263  throw new EamDbException("Correlation data source is null");
1264  }
1265 
1266  Connection conn = connect();
1267 
1268  PreparedStatement preparedUpdate = null;
1269  PreparedStatement preparedQuery = null;
1270  ResultSet resultSet = null;
1271 
1272  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1273 
1274  String sqlQuery
1275  = "SELECT id FROM "
1276  + tableName
1277  + " WHERE case_id=(SELECT id FROM cases WHERE case_uid=?) "
1278  + "AND data_source_id=(SELECT id FROM data_sources WHERE device_id=?) "
1279  + "AND value=? "
1280  + "AND file_path=?";
1281 
1282  String sqlUpdate
1283  = "UPDATE "
1284  + tableName
1285  + " SET known_status=?, comment=? "
1286  + "WHERE id=?";
1287 
1288  try {
1289  preparedQuery = conn.prepareStatement(sqlQuery);
1290  preparedQuery.setString(1, eamInstance.getCorrelationCase().getCaseUUID());
1291  preparedQuery.setString(2, eamInstance.getCorrelationDataSource().getDeviceID());
1292  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
1293  preparedQuery.setString(4, eamInstance.getFilePath());
1294  resultSet = preparedQuery.executeQuery();
1295  if (resultSet.next()) {
1296  int instance_id = resultSet.getInt("id");
1297  preparedUpdate = conn.prepareStatement(sqlUpdate);
1298 
1299  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
1300  // NOTE: if the user tags the same instance as BAD multiple times,
1301  // the comment from the most recent tagging is the one that will
1302  // prevail in the DB.
1303  if ("".equals(eamInstance.getComment())) {
1304  preparedUpdate.setNull(2, Types.INTEGER);
1305  } else {
1306  preparedUpdate.setString(2, eamInstance.getComment());
1307  }
1308  preparedUpdate.setInt(3, instance_id);
1309 
1310  preparedUpdate.executeUpdate();
1311  } else {
1312  // In this case, the user is tagging something that isn't in the database,
1313  // which means the case and/or datasource may also not be in the database.
1314  // We could improve effiency by keeping a list of all datasources and cases
1315  // in the database, but we don't expect the user to be tagging large numbers
1316  // of items (that didn't have the CE ingest module run on them) at once.
1317  CorrelationCase correlationCaseWithId = getCaseByUUID(eamInstance.getCorrelationCase().getCaseUUID());
1318  if (null == correlationCaseWithId) {
1319  correlationCaseWithId = newCase(eamInstance.getCorrelationCase());
1320  }
1321 
1322  if (null == getDataSource(correlationCaseWithId, eamInstance.getCorrelationDataSource().getDeviceID())) {
1323  newDataSource(eamInstance.getCorrelationDataSource());
1324  }
1325  eamArtifact.getInstances().get(0).setKnownStatus(knownStatus);
1326  addArtifact(eamArtifact);
1327  }
1328 
1329  } catch (SQLException ex) {
1330  throw new EamDbException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
1331  } finally {
1332  EamDbUtil.closeStatement(preparedUpdate);
1333  EamDbUtil.closeStatement(preparedQuery);
1334  EamDbUtil.closeResultSet(resultSet);
1335  EamDbUtil.closeConnection(conn);
1336  }
1337  }
1338 
1348  @Override
1349  public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException {
1350  if (aType == null) {
1351  throw new EamDbException("Correlation type is null");
1352  }
1353 
1354  Connection conn = connect();
1355 
1356  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1357 
1358  CorrelationAttributeInstance artifactInstance;
1359  PreparedStatement preparedStatement = null;
1360  ResultSet resultSet = null;
1361 
1362  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1363  String sql
1364  = "SELECT "
1365  + tableName
1366  + ".id, cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
1367  + tableName
1368  + " LEFT JOIN cases ON "
1369  + tableName
1370  + ".case_id=cases.id"
1371  + " LEFT JOIN data_sources ON "
1372  + tableName
1373  + ".data_source_id=data_sources.id"
1374  + " WHERE value=? AND known_status=?";
1375 
1376  try {
1377  preparedStatement = conn.prepareStatement(sql);
1378  preparedStatement.setString(1, value);
1379  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1380  resultSet = preparedStatement.executeQuery();
1381  while (resultSet.next()) {
1382  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet);
1383  artifactInstances.add(artifactInstance);
1384  }
1385  } catch (SQLException ex) {
1386  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1387  } finally {
1388  EamDbUtil.closeStatement(preparedStatement);
1389  EamDbUtil.closeResultSet(resultSet);
1390  EamDbUtil.closeConnection(conn);
1391  }
1392 
1393  return artifactInstances;
1394  }
1395 
1407  @Override
1408  public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttribute.Type aType) throws EamDbException {
1409  if (aType == null) {
1410  throw new EamDbException("Correlation type is null");
1411  }
1412 
1413  Connection conn = connect();
1414 
1415  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1416 
1417  CorrelationAttributeInstance artifactInstance;
1418  PreparedStatement preparedStatement = null;
1419  ResultSet resultSet = null;
1420 
1421  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1422  String sql
1423  = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
1424  + tableName
1425  + " LEFT JOIN cases ON "
1426  + tableName
1427  + ".case_id=cases.id"
1428  + " LEFT JOIN data_sources ON "
1429  + tableName
1430  + ".data_source_id=data_sources.id"
1431  + " WHERE known_status=?"
1432  + " GROUP BY "
1433  + tableName
1434  + ".value";
1435 
1436  try {
1437  preparedStatement = conn.prepareStatement(sql);
1438  preparedStatement.setByte(1, TskData.FileKnown.BAD.getFileKnownValue());
1439  resultSet = preparedStatement.executeQuery();
1440  while (resultSet.next()) {
1441  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet);
1442  artifactInstances.add(artifactInstance);
1443  }
1444  } catch (SQLException ex) {
1445  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1446  } finally {
1447  EamDbUtil.closeStatement(preparedStatement);
1448  EamDbUtil.closeResultSet(resultSet);
1449  EamDbUtil.closeConnection(conn);
1450  }
1451 
1452  return artifactInstances;
1453  }
1454 
1463  @Override
1464  public Long getCountArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException {
1465  if (aType == null) {
1466  throw new EamDbException("Correlation type is null");
1467  }
1468 
1469  Connection conn = connect();
1470 
1471  Long badInstances = 0L;
1472  PreparedStatement preparedStatement = null;
1473  ResultSet resultSet = null;
1474 
1475  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1476  String sql
1477  = "SELECT count(*) FROM "
1478  + tableName
1479  + " WHERE value=? AND known_status=?";
1480 
1481  try {
1482  preparedStatement = conn.prepareStatement(sql);
1483  preparedStatement.setString(1, value);
1484  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1485  resultSet = preparedStatement.executeQuery();
1486  resultSet.next();
1487  badInstances = resultSet.getLong(1);
1488  } catch (SQLException ex) {
1489  throw new EamDbException("Error getting count of notable artifact instances.", ex); // NON-NLS
1490  } finally {
1491  EamDbUtil.closeStatement(preparedStatement);
1492  EamDbUtil.closeResultSet(resultSet);
1493  EamDbUtil.closeConnection(conn);
1494  }
1495 
1496  return badInstances;
1497  }
1498 
1511  @Override
1512  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttribute.Type aType, String value) throws EamDbException {
1513  if (aType == null) {
1514  throw new EamDbException("Correlation type is null");
1515  }
1516 
1517  Connection conn = connect();
1518 
1519  Collection<String> caseNames = new LinkedHashSet<>();
1520 
1521  PreparedStatement preparedStatement = null;
1522  ResultSet resultSet = null;
1523 
1524  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1525  String sql
1526  = "SELECT DISTINCT case_name FROM "
1527  + tableName
1528  + " INNER JOIN cases ON "
1529  + tableName
1530  + ".case_id=cases.id WHERE "
1531  + tableName
1532  + ".value=? AND "
1533  + tableName
1534  + ".known_status=?";
1535 
1536  try {
1537  preparedStatement = conn.prepareStatement(sql);
1538  preparedStatement.setString(1, value);
1539  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1540  resultSet = preparedStatement.executeQuery();
1541  while (resultSet.next()) {
1542  caseNames.add(resultSet.getString("case_name"));
1543  }
1544  } catch (SQLException ex) {
1545  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1546  } finally {
1547  EamDbUtil.closeStatement(preparedStatement);
1548  EamDbUtil.closeResultSet(resultSet);
1549  EamDbUtil.closeConnection(conn);
1550  }
1551 
1552  return caseNames.stream().collect(Collectors.toList());
1553  }
1554 
1562  @Override
1563  public void deleteReferenceSet(int referenceSetID) throws EamDbException {
1564  deleteReferenceSetEntries(referenceSetID);
1565  deleteReferenceSetEntry(referenceSetID);
1566  }
1567 
1575  private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException {
1576  Connection conn = connect();
1577 
1578  PreparedStatement preparedStatement = null;
1579  String sql = "DELETE FROM reference_sets WHERE id=?";
1580 
1581  try {
1582  preparedStatement = conn.prepareStatement(sql);
1583  preparedStatement.setInt(1, referenceSetID);
1584  preparedStatement.executeUpdate();
1585  } catch (SQLException ex) {
1586  throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
1587  } finally {
1588  EamDbUtil.closeStatement(preparedStatement);
1589  EamDbUtil.closeConnection(conn);
1590  }
1591  }
1592 
1601  private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException {
1602  Connection conn = connect();
1603 
1604  PreparedStatement preparedStatement = null;
1605  String sql = "DELETE FROM %s WHERE reference_set_id=?";
1606 
1607  // When other reference types are added, this will need to loop over all the tables
1608  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID));
1609 
1610  try {
1611  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
1612  preparedStatement.setInt(1, referenceSetID);
1613  preparedStatement.executeUpdate();
1614  } catch (SQLException ex) {
1615  throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
1616  } finally {
1617  EamDbUtil.closeStatement(preparedStatement);
1618  EamDbUtil.closeConnection(conn);
1619  }
1620  }
1621 
1635  @Override
1636  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException {
1637  EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID);
1638  if (refSet == null) {
1639  return false;
1640  }
1641 
1642  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
1643  }
1644 
1656  @Override
1657  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException {
1658  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttribute.FILES_TYPE_ID);
1659  }
1660 
1670  @Override
1671  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException {
1672 
1673  Connection conn = connect();
1674 
1675  Long matchingInstances = 0L;
1676  PreparedStatement preparedStatement = null;
1677  ResultSet resultSet = null;
1678  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
1679 
1680  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
1681 
1682  try {
1683  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
1684  preparedStatement.setString(1, value);
1685  preparedStatement.setInt(2, referenceSetID);
1686  resultSet = preparedStatement.executeQuery();
1687  resultSet.next();
1688  matchingInstances = resultSet.getLong(1);
1689  } catch (SQLException ex) {
1690  throw new EamDbException("Error determining if value (" + value + ") is in reference set " + referenceSetID, ex); // NON-NLS
1691  } finally {
1692  EamDbUtil.closeStatement(preparedStatement);
1693  EamDbUtil.closeResultSet(resultSet);
1694  EamDbUtil.closeConnection(conn);
1695  }
1696 
1697  return 0 < matchingInstances;
1698  }
1699 
1708  @Override
1709  public boolean isArtifactKnownBadByReference(CorrelationAttribute.Type aType, String value) throws EamDbException {
1710  if (aType == null) {
1711  throw new EamDbException("Correlation type is null");
1712  }
1713 
1714  // TEMP: Only support file correlation type
1715  if (aType.getId() != CorrelationAttribute.FILES_TYPE_ID) {
1716  return false;
1717  }
1718 
1719  Connection conn = connect();
1720 
1721  Long badInstances = 0L;
1722  PreparedStatement preparedStatement = null;
1723  ResultSet resultSet = null;
1724  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
1725 
1726  try {
1727  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(aType)));
1728  preparedStatement.setString(1, value);
1729  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1730  resultSet = preparedStatement.executeQuery();
1731  resultSet.next();
1732  badInstances = resultSet.getLong(1);
1733  } catch (SQLException ex) {
1734  throw new EamDbException("Error determining if artifact is notable by reference.", ex); // NON-NLS
1735  } finally {
1736  EamDbUtil.closeStatement(preparedStatement);
1737  EamDbUtil.closeResultSet(resultSet);
1738  EamDbUtil.closeConnection(conn);
1739  }
1740 
1741  return 0 < badInstances;
1742  }
1750  @Override
1751  public void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
1752  if (type == null) {
1753  throw new EamDbException("Correlation type is null");
1754  }
1755 
1756  if (instanceTableCallback == null) {
1757  throw new EamDbException("Callback interface is null");
1758  }
1759 
1760  Connection conn = connect();
1761  PreparedStatement preparedStatement = null;
1762  ResultSet resultSet = null;
1763  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1764  StringBuilder sql = new StringBuilder();
1765  sql.append("select * from ");
1766  sql.append(tableName);
1767 
1768  try {
1769  preparedStatement = conn.prepareStatement(sql.toString());
1770  resultSet = preparedStatement.executeQuery();
1771  instanceTableCallback.process(resultSet);
1772  } catch (SQLException ex) {
1773  throw new EamDbException("Error getting all artifact instances from instances table", ex);
1774  } finally {
1775  EamDbUtil.closePreparedStatement(preparedStatement);
1776  EamDbUtil.closeResultSet(resultSet);
1777  EamDbUtil.closeConnection(conn);
1778  }
1779  }
1780 
1781  @Override
1782  public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
1783  if (eamOrg == null) {
1784  throw new EamDbException("EamOrganization is null");
1785  } else if (eamOrg.getOrgID() != -1) {
1786  throw new EamDbException("EamOrganization already has an ID");
1787  }
1788 
1789  Connection conn = connect();
1790  ResultSet generatedKeys = null;
1791  PreparedStatement preparedStatement = null;
1792  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
1793  + getConflictClause();
1794 
1795  try {
1796  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
1797  preparedStatement.setString(1, eamOrg.getName());
1798  preparedStatement.setString(2, eamOrg.getPocName());
1799  preparedStatement.setString(3, eamOrg.getPocEmail());
1800  preparedStatement.setString(4, eamOrg.getPocPhone());
1801 
1802  preparedStatement.executeUpdate();
1803  generatedKeys = preparedStatement.getGeneratedKeys();
1804  if (generatedKeys.next()) {
1805  eamOrg.setOrgID((int) generatedKeys.getLong(1));
1806  return eamOrg;
1807  } else {
1808  throw new SQLException("Creating user failed, no ID obtained.");
1809  }
1810  } catch (SQLException ex) {
1811  throw new EamDbException("Error inserting new organization.", ex); // NON-NLS
1812  } finally {
1813  EamDbUtil.closeStatement(preparedStatement);
1814  EamDbUtil.closeResultSet(generatedKeys);
1815  EamDbUtil.closeConnection(conn);
1816  }
1817  }
1818 
1826  @Override
1827  public List<EamOrganization> getOrganizations() throws EamDbException {
1828  Connection conn = connect();
1829 
1830  List<EamOrganization> orgs = new ArrayList<>();
1831  PreparedStatement preparedStatement = null;
1832  ResultSet resultSet = null;
1833  String sql = "SELECT * FROM organizations";
1834 
1835  try {
1836  preparedStatement = conn.prepareStatement(sql);
1837  resultSet = preparedStatement.executeQuery();
1838  while (resultSet.next()) {
1839  orgs.add(getEamOrganizationFromResultSet(resultSet));
1840  }
1841  return orgs;
1842 
1843  } catch (SQLException ex) {
1844  throw new EamDbException("Error getting all organizations.", ex); // NON-NLS
1845  } finally {
1846  EamDbUtil.closeStatement(preparedStatement);
1847  EamDbUtil.closeResultSet(resultSet);
1848  EamDbUtil.closeConnection(conn);
1849  }
1850  }
1851 
1861  @Override
1862  public EamOrganization getOrganizationByID(int orgID) throws EamDbException {
1863  Connection conn = connect();
1864 
1865  PreparedStatement preparedStatement = null;
1866  ResultSet resultSet = null;
1867  String sql = "SELECT * FROM organizations WHERE id=?";
1868 
1869  try {
1870  preparedStatement = conn.prepareStatement(sql);
1871  preparedStatement.setInt(1, orgID);
1872  resultSet = preparedStatement.executeQuery();
1873  resultSet.next();
1874  return getEamOrganizationFromResultSet(resultSet);
1875 
1876  } catch (SQLException ex) {
1877  throw new EamDbException("Error getting organization by id.", ex); // NON-NLS
1878  } finally {
1879  EamDbUtil.closeStatement(preparedStatement);
1880  EamDbUtil.closeResultSet(resultSet);
1881  EamDbUtil.closeConnection(conn);
1882  }
1883  }
1884 
1894  @Override
1895  public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException {
1896 
1897  EamGlobalSet globalSet = getReferenceSetByID(referenceSetID);
1898  if (globalSet == null) {
1899  throw new EamDbException("Reference set with ID " + referenceSetID + " not found");
1900  }
1901  return (getOrganizationByID(globalSet.getOrgID()));
1902  }
1903 
1911  private void testArgument(EamOrganization org) throws EamDbException {
1912  if (org == null) {
1913  throw new EamDbException("EamOrganization is null");
1914  } else if (org.getOrgID() == -1) {
1915  throw new EamDbException("Organization has -1 row ID");
1916  }
1917  }
1918 
1927  @Override
1928  public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException {
1929  testArgument(updatedOrganization);
1930 
1931  Connection conn = connect();
1932  PreparedStatement preparedStatement = null;
1933  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
1934  try {
1935  preparedStatement = conn.prepareStatement(sql);
1936  preparedStatement.setString(1, updatedOrganization.getName());
1937  preparedStatement.setString(2, updatedOrganization.getPocName());
1938  preparedStatement.setString(3, updatedOrganization.getPocEmail());
1939  preparedStatement.setString(4, updatedOrganization.getPocPhone());
1940  preparedStatement.setInt(5, updatedOrganization.getOrgID());
1941  preparedStatement.executeUpdate();
1942  } catch (SQLException ex) {
1943  throw new EamDbException("Error updating organization.", ex); // NON-NLS
1944  } finally {
1945  EamDbUtil.closeStatement(preparedStatement);
1946  EamDbUtil.closeConnection(conn);
1947  }
1948  }
1949 
1950  @Override
1951  public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException {
1952  testArgument(organizationToDelete);
1953 
1954  Connection conn = connect();
1955  PreparedStatement checkIfUsedStatement = null;
1956  ResultSet resultSet = null;
1957  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
1958  PreparedStatement deleteOrgStatement = null;
1959  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
1960  try {
1961  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
1962  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
1963  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
1964  resultSet = checkIfUsedStatement.executeQuery();
1965  resultSet.next();
1966  if (resultSet.getLong(1) > 0) {
1967  throw new EamDbException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
1968  }
1969  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
1970  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
1971  deleteOrgStatement.executeUpdate();
1972  } catch (SQLException ex) {
1973  throw new EamDbException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
1974  } finally {
1975  EamDbUtil.closeStatement(checkIfUsedStatement);
1976  EamDbUtil.closeStatement(deleteOrgStatement);
1977  EamDbUtil.closeResultSet(resultSet);
1978  EamDbUtil.closeConnection(conn);
1979  }
1980  }
1981 
1991  @Override
1992  public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException {
1993  if (eamGlobalSet == null) {
1994  throw new EamDbException("EamGlobalSet is null");
1995  }
1996 
1997  if (eamGlobalSet.getFileKnownStatus() == null) {
1998  throw new EamDbException("File known status on the EamGlobalSet is null");
1999  }
2000 
2001  if (eamGlobalSet.getType() == null) {
2002  throw new EamDbException("Type on the EamGlobalSet is null");
2003  }
2004 
2005  Connection conn = connect();
2006 
2007  PreparedStatement preparedStatement1 = null;
2008  PreparedStatement preparedStatement2 = null;
2009  ResultSet resultSet = null;
2010  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2011  + getConflictClause();
2012  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2013 
2014  try {
2015  preparedStatement1 = conn.prepareStatement(sql1);
2016  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2017  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2018  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2019  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2020  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2021  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2022  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2023 
2024  preparedStatement1.executeUpdate();
2025 
2026  preparedStatement2 = conn.prepareStatement(sql2);
2027  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2028  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2029  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2030  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2031 
2032  resultSet = preparedStatement2.executeQuery();
2033  resultSet.next();
2034  return resultSet.getInt("id");
2035 
2036  } catch (SQLException ex) {
2037  throw new EamDbException("Error inserting new global set.", ex); // NON-NLS
2038  } finally {
2039  EamDbUtil.closeStatement(preparedStatement1);
2040  EamDbUtil.closeStatement(preparedStatement2);
2041  EamDbUtil.closeResultSet(resultSet);
2042  EamDbUtil.closeConnection(conn);
2043  }
2044  }
2045 
2055  @Override
2056  public EamGlobalSet getReferenceSetByID(int referenceSetID) throws EamDbException {
2057  Connection conn = connect();
2058 
2059  PreparedStatement preparedStatement1 = null;
2060  ResultSet resultSet = null;
2061  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2062 
2063  try {
2064  preparedStatement1 = conn.prepareStatement(sql1);
2065  preparedStatement1.setInt(1, referenceSetID);
2066  resultSet = preparedStatement1.executeQuery();
2067  if (resultSet.next()) {
2068  return getEamGlobalSetFromResultSet(resultSet);
2069  } else {
2070  return null;
2071  }
2072 
2073  } catch (SQLException ex) {
2074  throw new EamDbException("Error getting reference set by id.", ex); // NON-NLS
2075  } finally {
2076  EamDbUtil.closeStatement(preparedStatement1);
2077  EamDbUtil.closeResultSet(resultSet);
2078  EamDbUtil.closeConnection(conn);
2079  }
2080  }
2081 
2091  @Override
2092  public List<EamGlobalSet> getAllReferenceSets(CorrelationAttribute.Type correlationType) throws EamDbException {
2093 
2094  if (correlationType == null) {
2095  throw new EamDbException("Correlation type is null");
2096  }
2097 
2098  List<EamGlobalSet> results = new ArrayList<>();
2099  Connection conn = connect();
2100 
2101  PreparedStatement preparedStatement1 = null;
2102  ResultSet resultSet = null;
2103  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
2104 
2105  try {
2106  preparedStatement1 = conn.prepareStatement(sql1);
2107  resultSet = preparedStatement1.executeQuery();
2108  while (resultSet.next()) {
2109  results.add(getEamGlobalSetFromResultSet(resultSet));
2110  }
2111 
2112  } catch (SQLException ex) {
2113  throw new EamDbException("Error getting reference sets.", ex); // NON-NLS
2114  } finally {
2115  EamDbUtil.closeStatement(preparedStatement1);
2116  EamDbUtil.closeResultSet(resultSet);
2117  EamDbUtil.closeConnection(conn);
2118  }
2119  return results;
2120  }
2121 
2131  @Override
2132  public void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttribute.Type correlationType) throws EamDbException {
2133  if (eamGlobalFileInstance.getKnownStatus() == null) {
2134  throw new EamDbException("Known status of EamGlobalFileInstance is null");
2135  }
2136  if (correlationType == null) {
2137  throw new EamDbException("Correlation type is null");
2138  }
2139 
2140  Connection conn = connect();
2141 
2142  PreparedStatement preparedStatement = null;
2143 
2144  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2145  + getConflictClause();
2146 
2147  try {
2148  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(correlationType)));
2149  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
2150  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
2151  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
2152  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
2153  preparedStatement.executeUpdate();
2154  } catch (SQLException ex) {
2155  throw new EamDbException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
2156  } finally {
2157  EamDbUtil.closeStatement(preparedStatement);
2158  EamDbUtil.closeConnection(conn);
2159  }
2160  }
2161 
2174  @Override
2175  public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException {
2176  Connection conn = connect();
2177 
2178  PreparedStatement preparedStatement1 = null;
2179  ResultSet resultSet = null;
2180  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
2181 
2182  try {
2183  preparedStatement1 = conn.prepareStatement(sql1);
2184  preparedStatement1.setString(1, referenceSetName);
2185  preparedStatement1.setString(2, version);
2186  resultSet = preparedStatement1.executeQuery();
2187  return (resultSet.next());
2188 
2189  } catch (SQLException ex) {
2190  throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName
2191  + " version: " + version, ex); // NON-NLS
2192  } finally {
2193  EamDbUtil.closeStatement(preparedStatement1);
2194  EamDbUtil.closeResultSet(resultSet);
2195  EamDbUtil.closeConnection(conn);
2196  }
2197  }
2198 
2204  @Override
2205  public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, CorrelationAttribute.Type contentType) throws EamDbException {
2206  if (contentType == null) {
2207  throw new EamDbException("Correlation type is null");
2208  }
2209  if (globalInstances == null) {
2210  throw new EamDbException("Null set of EamGlobalFileInstance");
2211  }
2212 
2213  Connection conn = connect();
2214 
2215  PreparedStatement bulkPs = null;
2216  try {
2217  conn.setAutoCommit(false);
2218 
2219  // FUTURE: have a separate global_files table for each Type.
2220  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2221  + getConflictClause();
2222 
2223  bulkPs = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(contentType)));
2224 
2225  for (EamGlobalFileInstance globalInstance : globalInstances) {
2226  if (globalInstance.getKnownStatus() == null) {
2227  throw new EamDbException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
2228  }
2229 
2230  bulkPs.setInt(1, globalInstance.getGlobalSetID());
2231  bulkPs.setString(2, globalInstance.getMD5Hash());
2232  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
2233  bulkPs.setString(4, globalInstance.getComment());
2234  bulkPs.addBatch();
2235  }
2236 
2237  bulkPs.executeBatch();
2238  conn.commit();
2239  } catch (SQLException | EamDbException ex) {
2240  try {
2241  conn.rollback();
2242  } catch (SQLException ex2) {
2243  // We're alredy in an error state
2244  }
2245  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
2246  } finally {
2247  EamDbUtil.closeStatement(bulkPs);
2248  EamDbUtil.closeConnection(conn);
2249  }
2250  }
2251 
2262  @Override
2263  public List<EamGlobalFileInstance> getReferenceInstancesByTypeValue(CorrelationAttribute.Type aType, String aValue) throws EamDbException {
2264  if (aType == null) {
2265  throw new EamDbException("Correlation type is null");
2266  }
2267 
2268  Connection conn = connect();
2269 
2270  List<EamGlobalFileInstance> globalFileInstances = new ArrayList<>();
2271  PreparedStatement preparedStatement1 = null;
2272  ResultSet resultSet = null;
2273  String sql1 = "SELECT * FROM %s WHERE value=?";
2274 
2275  try {
2276  preparedStatement1 = conn.prepareStatement(String.format(sql1, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2277  preparedStatement1.setString(1, aValue);
2278  resultSet = preparedStatement1.executeQuery();
2279  while (resultSet.next()) {
2280  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
2281  }
2282  return globalFileInstances;
2283 
2284  } catch (SQLException ex) {
2285  throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS
2286  } finally {
2287  EamDbUtil.closeStatement(preparedStatement1);
2288  EamDbUtil.closeResultSet(resultSet);
2289  EamDbUtil.closeConnection(conn);
2290  }
2291  }
2292 
2302  @Override
2303  public int newCorrelationType(CorrelationAttribute.Type newType) throws EamDbException {
2304  if (newType == null) {
2305  throw new EamDbException("Correlation type is null");
2306  }
2307 
2308  Connection conn = connect();
2309 
2310  PreparedStatement preparedStatement = null;
2311  PreparedStatement preparedStatementQuery = null;
2312  ResultSet resultSet = null;
2313  int typeId = 0;
2314  String insertSql;
2315  String querySql;
2316  // if we have a known ID, use it, if not (is -1) let the db assign it.
2317  if (-1 == newType.getId()) {
2318  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
2319  } else {
2320  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
2321  }
2322  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2323 
2324  try {
2325  preparedStatement = conn.prepareStatement(insertSql);
2326 
2327  if (-1 == newType.getId()) {
2328  preparedStatement.setString(1, newType.getDisplayName());
2329  preparedStatement.setString(2, newType.getDbTableName());
2330  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
2331  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
2332  } else {
2333  preparedStatement.setInt(1, newType.getId());
2334  preparedStatement.setString(2, newType.getDisplayName());
2335  preparedStatement.setString(3, newType.getDbTableName());
2336  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
2337  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
2338  }
2339 
2340  preparedStatement.executeUpdate();
2341 
2342  preparedStatementQuery = conn.prepareStatement(querySql);
2343  preparedStatementQuery.setString(1, newType.getDisplayName());
2344  preparedStatementQuery.setString(2, newType.getDbTableName());
2345 
2346  resultSet = preparedStatementQuery.executeQuery();
2347  if (resultSet.next()) {
2348  CorrelationAttribute.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2349  typeId = correlationType.getId();
2350  }
2351  } catch (SQLException ex) {
2352  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2353  } finally {
2354  EamDbUtil.closeStatement(preparedStatement);
2355  EamDbUtil.closeStatement(preparedStatementQuery);
2356  EamDbUtil.closeResultSet(resultSet);
2357  EamDbUtil.closeConnection(conn);
2358  }
2359  return typeId;
2360  }
2361 
2362  @Override
2363  public List<CorrelationAttribute.Type> getDefinedCorrelationTypes() throws EamDbException {
2364  Connection conn = connect();
2365 
2366  List<CorrelationAttribute.Type> aTypes = new ArrayList<>();
2367  PreparedStatement preparedStatement = null;
2368  ResultSet resultSet = null;
2369  String sql = "SELECT * FROM correlation_types";
2370 
2371  try {
2372  preparedStatement = conn.prepareStatement(sql);
2373  resultSet = preparedStatement.executeQuery();
2374  while (resultSet.next()) {
2375  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2376  }
2377  return aTypes;
2378 
2379  } catch (SQLException ex) {
2380  throw new EamDbException("Error getting all correlation types.", ex); // NON-NLS
2381  } finally {
2382  EamDbUtil.closeStatement(preparedStatement);
2383  EamDbUtil.closeResultSet(resultSet);
2384  EamDbUtil.closeConnection(conn);
2385  }
2386  }
2387 
2397  @Override
2398  public List<CorrelationAttribute.Type> getEnabledCorrelationTypes() throws EamDbException {
2399  Connection conn = connect();
2400 
2401  List<CorrelationAttribute.Type> aTypes = new ArrayList<>();
2402  PreparedStatement preparedStatement = null;
2403  ResultSet resultSet = null;
2404  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
2405 
2406  try {
2407  preparedStatement = conn.prepareStatement(sql);
2408  resultSet = preparedStatement.executeQuery();
2409  while (resultSet.next()) {
2410  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2411  }
2412  return aTypes;
2413 
2414  } catch (SQLException ex) {
2415  throw new EamDbException("Error getting enabled correlation types.", ex); // NON-NLS
2416  } finally {
2417  EamDbUtil.closeStatement(preparedStatement);
2418  EamDbUtil.closeResultSet(resultSet);
2419  EamDbUtil.closeConnection(conn);
2420  }
2421  }
2422 
2432  @Override
2433  public List<CorrelationAttribute.Type> getSupportedCorrelationTypes() throws EamDbException {
2434  Connection conn = connect();
2435 
2436  List<CorrelationAttribute.Type> aTypes = new ArrayList<>();
2437  PreparedStatement preparedStatement = null;
2438  ResultSet resultSet = null;
2439  String sql = "SELECT * FROM correlation_types WHERE supported=1";
2440 
2441  try {
2442  preparedStatement = conn.prepareStatement(sql);
2443  resultSet = preparedStatement.executeQuery();
2444  while (resultSet.next()) {
2445  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2446  }
2447  return aTypes;
2448 
2449  } catch (SQLException ex) {
2450  throw new EamDbException("Error getting supported correlation types.", ex); // NON-NLS
2451  } finally {
2452  EamDbUtil.closeStatement(preparedStatement);
2453  EamDbUtil.closeResultSet(resultSet);
2454  EamDbUtil.closeConnection(conn);
2455  }
2456  }
2457 
2465  @Override
2466  public void updateCorrelationType(CorrelationAttribute.Type aType) throws EamDbException {
2467  Connection conn = connect();
2468 
2469  PreparedStatement preparedStatement = null;
2470  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
2471 
2472  try {
2473  preparedStatement = conn.prepareStatement(sql);
2474  preparedStatement.setString(1, aType.getDisplayName());
2475  preparedStatement.setString(2, aType.getDbTableName());
2476  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
2477  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
2478  preparedStatement.setInt(5, aType.getId());
2479  preparedStatement.executeUpdate();
2480 
2481  } catch (SQLException ex) {
2482  throw new EamDbException("Error updating correlation type.", ex); // NON-NLS
2483  } finally {
2484  EamDbUtil.closeStatement(preparedStatement);
2485  EamDbUtil.closeConnection(conn);
2486  }
2487 
2488  }
2489 
2499  @Override
2500  public CorrelationAttribute.Type getCorrelationTypeById(int typeId) throws EamDbException {
2501  Connection conn = connect();
2502 
2503  CorrelationAttribute.Type aType;
2504  PreparedStatement preparedStatement = null;
2505  ResultSet resultSet = null;
2506  String sql = "SELECT * FROM correlation_types WHERE id=?";
2507 
2508  try {
2509  preparedStatement = conn.prepareStatement(sql);
2510  preparedStatement.setInt(1, typeId);
2511  resultSet = preparedStatement.executeQuery();
2512  if (resultSet.next()) {
2513  aType = getCorrelationTypeFromResultSet(resultSet);
2514  return aType;
2515  } else {
2516  throw new EamDbException("Failed to find entry for correlation type ID = " + typeId);
2517  }
2518 
2519  } catch (SQLException ex) {
2520  throw new EamDbException("Error getting correlation type by id.", ex); // NON-NLS
2521  } finally {
2522  EamDbUtil.closeStatement(preparedStatement);
2523  EamDbUtil.closeResultSet(resultSet);
2524  EamDbUtil.closeConnection(conn);
2525  }
2526  }
2527 
2538  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
2539  if (null == resultSet) {
2540  return null;
2541  }
2542 
2543  EamOrganization eamOrg = null;
2544 
2545  resultSet.getInt("org_id");
2546  if (!resultSet.wasNull()) {
2547 
2548  eamOrg = new EamOrganization(resultSet.getInt("org_id"),
2549  resultSet.getString("org_name"),
2550  resultSet.getString("poc_name"),
2551  resultSet.getString("poc_email"),
2552  resultSet.getString("poc_phone"));
2553  }
2554 
2555  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name"));
2556  eamCase.setOrg(eamOrg);
2557  eamCase.setCreationDate(resultSet.getString("creation_date"));
2558  eamCase.setCaseNumber(resultSet.getString("case_number"));
2559  eamCase.setExaminerName(resultSet.getString("examiner_name"));
2560  eamCase.setExaminerEmail(resultSet.getString("examiner_email"));
2561  eamCase.setExaminerPhone(resultSet.getString("examiner_phone"));
2562  eamCase.setNotes(resultSet.getString("notes"));
2563 
2564  return eamCase;
2565  }
2566 
2567  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
2568  if (null == resultSet) {
2569  return null;
2570  }
2571 
2572  CorrelationDataSource eamDataSource = new CorrelationDataSource(
2573  resultSet.getInt("case_id"),
2574  resultSet.getInt("id"),
2575  resultSet.getString("device_id"),
2576  resultSet.getString("name")
2577  );
2578 
2579  return eamDataSource;
2580  }
2581 
2582  private CorrelationAttribute.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws EamDbException, SQLException {
2583  if (null == resultSet) {
2584  return null;
2585  }
2586 
2587  CorrelationAttribute.Type eamArtifactType = new CorrelationAttribute.Type(
2588  resultSet.getInt("id"),
2589  resultSet.getString("display_name"),
2590  resultSet.getString("db_table_name"),
2591  resultSet.getBoolean("supported"),
2592  resultSet.getBoolean("enabled")
2593  );
2594 
2595  return eamArtifactType;
2596  }
2597 
2608  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
2609  if (null == resultSet) {
2610  return null;
2611  }
2612  // @@@ We should have data source ID in the previous query instead of passing -1 into the below constructor
2613  return new CorrelationAttributeInstance(
2614  resultSet.getInt("id"),
2615  new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
2616  new CorrelationDataSource(resultSet.getInt("case_id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name")),
2617  resultSet.getString("file_path"),
2618  resultSet.getString("comment"),
2619  TskData.FileKnown.valueOf(resultSet.getByte("known_status"))
2620  );
2621  }
2622 
2623  private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
2624  if (null == resultSet) {
2625  return null;
2626  }
2627 
2628  return new EamOrganization(
2629  resultSet.getInt("id"),
2630  resultSet.getString("org_name"),
2631  resultSet.getString("poc_name"),
2632  resultSet.getString("poc_email"),
2633  resultSet.getString("poc_phone")
2634  );
2635  }
2636 
2637  private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
2638  if (null == resultSet) {
2639  return null;
2640  }
2641 
2642  return new EamGlobalSet(
2643  resultSet.getInt("id"),
2644  resultSet.getInt("org_id"),
2645  resultSet.getString("set_name"),
2646  resultSet.getString("version"),
2647  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
2648  resultSet.getBoolean("read_only"),
2649  EamDb.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
2650  LocalDate.parse(resultSet.getString("import_date"))
2651  );
2652  }
2653 
2654  private EamGlobalFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
2655  if (null == resultSet) {
2656  return null;
2657  }
2658 
2659  return new EamGlobalFileInstance(
2660  resultSet.getInt("id"),
2661  resultSet.getInt("reference_set_id"),
2662  resultSet.getString("value"),
2663  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
2664  resultSet.getString("comment")
2665  );
2666  }
2667 
2673  @Override
2674  public void upgradeSchema() throws EamDbException, SQLException {
2675 
2676  ResultSet resultSet = null;
2677  Statement statement = null;
2678  Connection conn = null;
2679  try {
2680 
2681  conn = connect();
2682  conn.setAutoCommit(false);
2683  statement = conn.createStatement();
2684 
2685  int minorVersion = 0;
2686  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'");
2687  if (resultSet.next()) {
2688  String minorVersionStr = resultSet.getString("value");
2689  try {
2690  minorVersion = Integer.parseInt(minorVersionStr);
2691  } catch (NumberFormatException ex) {
2692  throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", ex);
2693  }
2694  }
2695 
2696  int majorVersion = 0;
2697  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_VERSION'");
2698  if (resultSet.next()) {
2699  String majorVersionStr = resultSet.getString("value");
2700  try {
2701  majorVersion = Integer.parseInt(majorVersionStr);
2702  } catch (NumberFormatException ex) {
2703  throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", ex);
2704  }
2705  }
2706 
2707  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
2708  if (dbSchemaVersion.equals(CURRENT_DB_SCHEMA_VERSION)) {
2709  logger.log(Level.INFO, "Central Repository is up to date");
2710  return;
2711  }
2712 
2713  // Update from 1.0 to 1.1
2714  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
2715  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
2716  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
2717  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
2718 
2719  // There's an outide chance that the user has already made an organization with the default name,
2720  // and the default org being missing will not impact any database operations, so continue on
2721  // regardless of whether this succeeds.
2722  EamDbUtil.insertDefaultOrganization(conn);
2723  }
2724 
2725  if (!updateSchemaVersion(conn)) {
2726  throw new EamDbException("Error updating schema version");
2727  }
2728 
2729  conn.commit();
2730  logger.log(Level.INFO, "Central Repository upgraded to version " + CURRENT_DB_SCHEMA_VERSION);
2731  } catch (SQLException | EamDbException ex) {
2732  try {
2733  if (conn != null) {
2734  conn.rollback();
2735  }
2736  } catch (SQLException ex2) {
2737  logger.log(Level.SEVERE, "Database rollback failed", ex2);
2738  }
2739  throw ex;
2740  } finally {
2741  EamDbUtil.closeResultSet(resultSet);
2742  EamDbUtil.closeStatement(statement);
2743  EamDbUtil.closeConnection(conn);
2744  }
2745  }
2746 
2747 }
CorrelationAttribute.Type getCorrelationTypeById(int typeId)
void addInstance(CorrelationAttributeInstance artifactInstance)
static String correlationTypeToReferenceTableName(CorrelationAttribute.Type type)
Definition: EamDbUtil.java:360
static String correlationTypeToInstanceTableName(CorrelationAttribute.Type type)
Definition: EamDbUtil.java:349
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void closePreparedStatement(PreparedStatement preparedStatement)
Definition: EamDbUtil.java:374

Copyright © 2012-2016 Basis Technology. Generated on: Mon Jun 18 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.