Autopsy  4.10.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-2019 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 com.google.common.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import com.google.common.cache.CacheLoader;
24 import java.net.UnknownHostException;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Collection;
28 import java.util.LinkedHashSet;
29 import java.util.stream.Collectors;
30 import java.sql.Connection;
31 import java.sql.PreparedStatement;
32 import java.sql.ResultSet;
33 import java.sql.SQLException;
34 import java.sql.Statement;
35 import java.sql.Types;
36 import java.time.LocalDate;
37 import java.util.Arrays;
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.ExecutionException;
42 import java.util.concurrent.TimeUnit;
43 import java.util.logging.Level;
44 import org.openide.util.NbBundle.Messages;
46 import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion;
50 import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
51 import org.sleuthkit.datamodel.TskData;
52 
58 abstract class AbstractSqlEamDb implements EamDb {
59 
60  private final static Logger logger = Logger.getLogger(AbstractSqlEamDb.class.getName());
61  static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_VERSION";
62  static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
63  static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
64  static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
65  static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 3);
66 
67  protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
68 
69  private int bulkArtifactsCount;
70  protected int bulkArtifactsThreshold;
71  private final Map<String, Collection<CorrelationAttributeInstance>> bulkArtifacts;
72  private static final int CASE_CACHE_TIMEOUT = 5;
73  private static final int DATA_SOURCE_CACHE_TIMEOUT = 5;
74  private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
75  private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
76  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
77  build();
78  private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
79  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
80  build();
81  private static final Cache<String, CorrelationDataSource> dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
82  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
83  build();
84  private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
85  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
86  build();
87  // Maximum length for the value column in the instance tables
88  static final int MAX_VALUE_LENGTH = 256;
89 
90  // number of instances to keep in bulk queue before doing an insert.
91  // Update Test code if this changes. It's hard coded there.
92  static final int DEFAULT_BULK_THRESHHOLD = 1000;
93 
99  protected AbstractSqlEamDb() throws EamDbException {
100  bulkArtifactsCount = 0;
101  bulkArtifacts = new HashMap<>();
102 
103  defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
104  defaultCorrelationTypes.forEach((type) -> {
105  bulkArtifacts.put(EamDbUtil.correlationTypeToInstanceTableName(type), new ArrayList<>());
106  });
107  }
108 
112  protected abstract Connection connect(boolean foreignKeys) throws EamDbException;
113 
117  protected abstract Connection connect() throws EamDbException;
118 
127  @Override
128  public void newDbInfo(String name, String value) throws EamDbException {
129  Connection conn = connect();
130 
131  PreparedStatement preparedStatement = null;
132  String sql = "INSERT INTO db_info (name, value) VALUES (?, ?) "
133  + getConflictClause();
134  try {
135  preparedStatement = conn.prepareStatement(sql);
136  preparedStatement.setString(1, name);
137  preparedStatement.setString(2, value);
138  preparedStatement.executeUpdate();
139  } catch (SQLException ex) {
140  throw new EamDbException("Error adding new name/value pair to db_info.", ex);
141  } finally {
142  EamDbUtil.closeStatement(preparedStatement);
144  }
145 
146  }
147 
148  @Override
149  public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws EamDbException {
150  Connection conn = connect();
151  PreparedStatement preparedStatement = null;
152  String sql = "UPDATE data_sources SET datasource_obj_id=? WHERE id=?";
153  try {
154  preparedStatement = conn.prepareStatement(sql);
155  preparedStatement.setLong(1, dataSourceObjectId);
156  preparedStatement.setInt(2, rowId);
157  preparedStatement.executeUpdate();
158  } catch (SQLException ex) {
159  throw new EamDbException("Error updating data source object id for data_sources row " + rowId, ex);
160  } finally {
161  EamDbUtil.closeStatement(preparedStatement);
163  }
164  }
165 
175  @Override
176  public String getDbInfo(String name) throws EamDbException {
177  Connection conn = connect();
178 
179  PreparedStatement preparedStatement = null;
180  ResultSet resultSet = null;
181  String value = null;
182  String sql = "SELECT value FROM db_info WHERE name=?";
183  try {
184  preparedStatement = conn.prepareStatement(sql);
185  preparedStatement.setString(1, name);
186  resultSet = preparedStatement.executeQuery();
187  if (resultSet.next()) {
188  value = resultSet.getString("value");
189  }
190  } catch (SQLException ex) {
191  throw new EamDbException("Error getting value for name.", ex);
192  } finally {
193  EamDbUtil.closeStatement(preparedStatement);
194  EamDbUtil.closeResultSet(resultSet);
196  }
197 
198  return value;
199  }
200 
204  protected final void clearCaches() {
205  typeCache.invalidateAll();
206  caseCacheByUUID.invalidateAll();
207  caseCacheById.invalidateAll();
208  dataSourceCacheByDsObjectId.invalidateAll();
209  dataSourceCacheById.invalidateAll();
210  }
211 
220  @Override
221  public void updateDbInfo(String name, String value) throws EamDbException {
222  Connection conn = connect();
223 
224  PreparedStatement preparedStatement = null;
225  String sql = "UPDATE db_info SET value=? WHERE name=?";
226  try {
227  preparedStatement = conn.prepareStatement(sql);
228  preparedStatement.setString(1, value);
229  preparedStatement.setString(2, name);
230  preparedStatement.executeUpdate();
231  } catch (SQLException ex) {
232  throw new EamDbException("Error updating value for name.", ex);
233  } finally {
234  EamDbUtil.closeStatement(preparedStatement);
236  }
237  }
238 
248  @Override
249  public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
250 
251  if (eamCase.getCaseUUID() == null) {
252  throw new EamDbException("Case UUID is null");
253  }
254 
255  // check if there is already an existing CorrelationCase for this Case
256  CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
257  if (cRCase != null) {
258  return cRCase;
259  }
260 
261  Connection conn = connect();
262  PreparedStatement preparedStatement = null;
263 
264  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
265  + "examiner_name, examiner_email, examiner_phone, notes) "
266  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
267  + getConflictClause();
268  ResultSet resultSet = null;
269  try {
270  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
271 
272  preparedStatement.setString(1, eamCase.getCaseUUID());
273  if (null == eamCase.getOrg()) {
274  preparedStatement.setNull(2, Types.INTEGER);
275  } else {
276  preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
277  }
278  preparedStatement.setString(3, eamCase.getDisplayName());
279  preparedStatement.setString(4, eamCase.getCreationDate());
280  if ("".equals(eamCase.getCaseNumber())) {
281  preparedStatement.setNull(5, Types.INTEGER);
282  } else {
283  preparedStatement.setString(5, eamCase.getCaseNumber());
284  }
285  if ("".equals(eamCase.getExaminerName())) {
286  preparedStatement.setNull(6, Types.INTEGER);
287  } else {
288  preparedStatement.setString(6, eamCase.getExaminerName());
289  }
290  if ("".equals(eamCase.getExaminerEmail())) {
291  preparedStatement.setNull(7, Types.INTEGER);
292  } else {
293  preparedStatement.setString(7, eamCase.getExaminerEmail());
294  }
295  if ("".equals(eamCase.getExaminerPhone())) {
296  preparedStatement.setNull(8, Types.INTEGER);
297  } else {
298  preparedStatement.setString(8, eamCase.getExaminerPhone());
299  }
300  if ("".equals(eamCase.getNotes())) {
301  preparedStatement.setNull(9, Types.INTEGER);
302  } else {
303  preparedStatement.setString(9, eamCase.getNotes());
304  }
305 
306  preparedStatement.executeUpdate();
307  //update the case in the caches
308  resultSet = preparedStatement.getGeneratedKeys();
309  if (!resultSet.next()) {
310  throw new EamDbException(String.format("Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
311  }
312  int caseID = resultSet.getInt(1); //last_insert_rowid()
313  CorrelationCase correlationCase = new CorrelationCase(caseID, eamCase.getCaseUUID(), eamCase.getOrg(),
314  eamCase.getDisplayName(), eamCase.getCreationDate(), eamCase.getCaseNumber(), eamCase.getExaminerName(),
315  eamCase.getExaminerEmail(), eamCase.getExaminerPhone(), eamCase.getNotes());
316  caseCacheByUUID.put(eamCase.getCaseUUID(), correlationCase);
317  caseCacheById.put(caseID, correlationCase);
318  } catch (SQLException ex) {
319  throw new EamDbException("Error inserting new case.", ex); // NON-NLS
320  } finally {
321  EamDbUtil.closeResultSet(resultSet);
322  EamDbUtil.closeStatement(preparedStatement);
324  }
325 
326  // get a new version with the updated ID
327  return getCaseByUUID(eamCase.getCaseUUID());
328  }
329 
335  @Override
336  public CorrelationCase newCase(Case autopsyCase) throws EamDbException {
337  if (autopsyCase == null) {
338  throw new EamDbException("Case is null");
339  }
340 
341  CorrelationCase curCeCase = new CorrelationCase(
342  -1,
343  autopsyCase.getName(), // unique case ID
345  autopsyCase.getDisplayName(),
346  autopsyCase.getCreatedDate(),
347  autopsyCase.getNumber(),
348  autopsyCase.getExaminer(),
349  autopsyCase.getExaminerEmail(),
350  autopsyCase.getExaminerPhone(),
351  autopsyCase.getCaseNotes());
352  return newCase(curCeCase);
353  }
354 
355  @Override
356  public CorrelationCase getCase(Case autopsyCase) throws EamDbException {
357  return getCaseByUUID(autopsyCase.getName());
358  }
359 
365  @Override
366  public void updateCase(CorrelationCase eamCase) throws EamDbException {
367  if (eamCase == null) {
368  throw new EamDbException("Correlation case is null");
369  }
370 
371  Connection conn = connect();
372 
373  PreparedStatement preparedStatement = null;
374  String sql = "UPDATE cases "
375  + "SET org_id=?, case_name=?, creation_date=?, case_number=?, examiner_name=?, examiner_email=?, examiner_phone=?, notes=? "
376  + "WHERE case_uid=?";
377 
378  try {
379  preparedStatement = conn.prepareStatement(sql);
380 
381  if (null == eamCase.getOrg()) {
382  preparedStatement.setNull(1, Types.INTEGER);
383  } else {
384  preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
385  }
386  preparedStatement.setString(2, eamCase.getDisplayName());
387  preparedStatement.setString(3, eamCase.getCreationDate());
388 
389  if ("".equals(eamCase.getCaseNumber())) {
390  preparedStatement.setNull(4, Types.INTEGER);
391  } else {
392  preparedStatement.setString(4, eamCase.getCaseNumber());
393  }
394  if ("".equals(eamCase.getExaminerName())) {
395  preparedStatement.setNull(5, Types.INTEGER);
396  } else {
397  preparedStatement.setString(5, eamCase.getExaminerName());
398  }
399  if ("".equals(eamCase.getExaminerEmail())) {
400  preparedStatement.setNull(6, Types.INTEGER);
401  } else {
402  preparedStatement.setString(6, eamCase.getExaminerEmail());
403  }
404  if ("".equals(eamCase.getExaminerPhone())) {
405  preparedStatement.setNull(7, Types.INTEGER);
406  } else {
407  preparedStatement.setString(7, eamCase.getExaminerPhone());
408  }
409  if ("".equals(eamCase.getNotes())) {
410  preparedStatement.setNull(8, Types.INTEGER);
411  } else {
412  preparedStatement.setString(8, eamCase.getNotes());
413  }
414 
415  preparedStatement.setString(9, eamCase.getCaseUUID());
416 
417  preparedStatement.executeUpdate();
418  //update the case in the cache
419  caseCacheById.put(eamCase.getID(), eamCase);
420  caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
421  } catch (SQLException ex) {
422  throw new EamDbException("Error updating case.", ex); // NON-NLS
423  } finally {
424  EamDbUtil.closeStatement(preparedStatement);
426  }
427  }
428 
436  @Override
437  public CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException {
438  try {
439  return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
440  } catch (CacheLoader.InvalidCacheLoadException ignored) {
441  //lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
442  return null;
443  } catch (ExecutionException ex) {
444  throw new EamDbException("Error getting autopsy case from Central repo", ex);
445  }
446  }
447 
455  private CorrelationCase getCaseByUUIDFromCr(String caseUUID) throws EamDbException {
456  Connection conn = connect();
457 
458  CorrelationCase eamCaseResult = null;
459  PreparedStatement preparedStatement = null;
460  ResultSet resultSet = null;
461 
462  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
463  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
464  + "FROM cases "
465  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
466  + "WHERE case_uid=?";
467 
468  try {
469  preparedStatement = conn.prepareStatement(sql);
470  preparedStatement.setString(1, caseUUID);
471  resultSet = preparedStatement.executeQuery();
472  if (resultSet.next()) {
473  eamCaseResult = getEamCaseFromResultSet(resultSet);
474  }
475  if (eamCaseResult != null) {
476  //Update the version in the other cache
477  caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
478  }
479  } catch (SQLException ex) {
480  throw new EamDbException("Error getting case details.", ex); // NON-NLS
481  } finally {
482  EamDbUtil.closeStatement(preparedStatement);
483  EamDbUtil.closeResultSet(resultSet);
485  }
486 
487  return eamCaseResult;
488  }
489 
497  @Override
498  public CorrelationCase getCaseById(int caseId) throws EamDbException {
499  try {
500  return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
501  } catch (CacheLoader.InvalidCacheLoadException ignored) {
502  //lambda valueloader returned a null value and cache can not store null values this is normal if the case does not exist in the central repo yet
503  return null;
504  } catch (ExecutionException ex) {
505  throw new EamDbException("Error getting autopsy case from Central repo", ex);
506  }
507  }
508 
516  private CorrelationCase getCaseByIdFromCr(int caseId) throws EamDbException {
517  Connection conn = connect();
518 
519  CorrelationCase eamCaseResult = null;
520  PreparedStatement preparedStatement = null;
521  ResultSet resultSet = null;
522 
523  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
524  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
525  + "FROM cases "
526  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
527  + "WHERE cases.id=?";
528  try {
529  preparedStatement = conn.prepareStatement(sql);
530  preparedStatement.setInt(1, caseId);
531  resultSet = preparedStatement.executeQuery();
532  if (resultSet.next()) {
533  eamCaseResult = getEamCaseFromResultSet(resultSet);
534  }
535  if (eamCaseResult != null) {
536  //Update the version in the other cache
537  caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
538  }
539  } catch (SQLException ex) {
540  throw new EamDbException("Error getting case details.", ex); // NON-NLS
541  } finally {
542  EamDbUtil.closeStatement(preparedStatement);
543  EamDbUtil.closeResultSet(resultSet);
545  }
546 
547  return eamCaseResult;
548  }
549 
555  @Override
556  public List<CorrelationCase> getCases() throws EamDbException {
557  Connection conn = connect();
558 
559  List<CorrelationCase> cases = new ArrayList<>();
560  CorrelationCase eamCaseResult;
561  PreparedStatement preparedStatement = null;
562  ResultSet resultSet = null;
563 
564  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
565  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
566  + "FROM cases "
567  + "LEFT JOIN organizations ON cases.org_id=organizations.id";
568 
569  try {
570  preparedStatement = conn.prepareStatement(sql);
571  resultSet = preparedStatement.executeQuery();
572  while (resultSet.next()) {
573  eamCaseResult = getEamCaseFromResultSet(resultSet);
574  cases.add(eamCaseResult);
575  }
576  } catch (SQLException ex) {
577  throw new EamDbException("Error getting all cases.", ex); // NON-NLS
578  } finally {
579  EamDbUtil.closeStatement(preparedStatement);
580  EamDbUtil.closeResultSet(resultSet);
582  }
583 
584  return cases;
585  }
586 
597  private static String getDataSourceByDSObjectIdCacheKey(int caseId, Long dataSourceObjectId) {
598  return "Case" + caseId + "DsObjectId" + dataSourceObjectId; //NON-NLS
599  }
600 
610  private static String getDataSourceByIdCacheKey(int caseId, int dataSourceId) {
611  return "Case" + caseId + "Id" + dataSourceId; //NON-NLS
612  }
613 
619  @Override
620  public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws EamDbException {
621  if (eamDataSource.getCaseID() == -1) {
622  throw new EamDbException("Case ID is -1");
623  }
624  if (eamDataSource.getDeviceID() == null) {
625  throw new EamDbException("Device ID is null");
626  }
627  if (eamDataSource.getName() == null) {
628  throw new EamDbException("Name is null");
629  }
630  if (eamDataSource.getID() != -1) {
631  // This data source is already in the central repo
632  return eamDataSource;
633  }
634 
635  Connection conn = connect();
636 
637  PreparedStatement preparedStatement = null;
638  //The conflict clause exists in case multiple nodes are trying to add the data source because it did not exist at the same time
639  String sql = "INSERT INTO data_sources(device_id, case_id, name, datasource_obj_id, md5, sha1, sha256) VALUES (?, ?, ?, ?, ?, ?, ?) "
640  + getConflictClause();
641  ResultSet resultSet = null;
642  try {
643  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
644 
645  preparedStatement.setString(1, eamDataSource.getDeviceID());
646  preparedStatement.setInt(2, eamDataSource.getCaseID());
647  preparedStatement.setString(3, eamDataSource.getName());
648  preparedStatement.setLong(4, eamDataSource.getDataSourceObjectID());
649  preparedStatement.setString(5, eamDataSource.getMd5());
650  preparedStatement.setString(6, eamDataSource.getSha1());
651  preparedStatement.setString(7, eamDataSource.getSha256());
652 
653  preparedStatement.executeUpdate();
654  resultSet = preparedStatement.getGeneratedKeys();
655  if (!resultSet.next()) {
656  /*
657  * If nothing was inserted, then return the data source that
658  * exists in the Central Repository.
659  *
660  * This is expected to occur with PostgreSQL Central Repository
661  * databases.
662  */
663  try {
664  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
665  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
666  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
667  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
668  throw new EamDbException(String.format("Unable to to INSERT or get data source %s in central repo:", eamDataSource.getName()), getException);
669  }
670  } else {
671  //if a new data source was added to the central repository update the caches to include it and return it
672  int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
673  CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName(), eamDataSource.getDataSourceObjectID(), eamDataSource.getMd5(), eamDataSource.getSha1(), eamDataSource.getSha256());
674  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(dataSource.getCaseID(), dataSource.getDataSourceObjectID()), dataSource);
675  dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
676  return dataSource;
677  }
678 
679  } catch (SQLException insertException) {
680  /*
681  * If an exception was thrown causing us to not return a new data
682  * source, attempt to get an existing data source with the same case
683  * ID and data source object ID.
684  *
685  * This exception block is expected to occur with SQLite Central
686  * Repository databases.
687  */
688  try {
689  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
690  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
691  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
692  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
693  throw new EamDbException(String.format("Unable to to INSERT or get data source %s in central repo, insert failed due to Exception: %s", eamDataSource.getName(), insertException.getMessage()), getException);
694  }
695  } finally {
696  EamDbUtil.closeResultSet(resultSet);
697  EamDbUtil.closeStatement(preparedStatement);
699  }
700  }
701 
713  @Override
714  public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) throws EamDbException {
715 
716  if (correlationCase == null) {
717  throw new EamDbException("Correlation case is null");
718  }
719  try {
720  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase.getID(), dataSourceObjectId));
721  } catch (CacheLoader.InvalidCacheLoadException ignored) {
722  //lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
723  return null;
724  } catch (ExecutionException ex) {
725  throw new EamDbException("Error getting data source from central repository", ex);
726  }
727  }
728 
741  private CorrelationDataSource getDataSourceFromCr(int correlationCaseId, Long dataSourceObjectId) throws EamDbException {
742  Connection conn = connect();
743 
744  CorrelationDataSource eamDataSourceResult = null;
745  PreparedStatement preparedStatement = null;
746  ResultSet resultSet = null;
747 
748  String sql = "SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; // NON-NLS
749 
750  try {
751  preparedStatement = conn.prepareStatement(sql);
752  preparedStatement.setLong(1, dataSourceObjectId);
753  preparedStatement.setInt(2, correlationCaseId);
754  resultSet = preparedStatement.executeQuery();
755  if (resultSet.next()) {
756  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
757  }
758  if (eamDataSourceResult != null) {
759  dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCaseId, eamDataSourceResult.getID()), eamDataSourceResult);
760  }
761  } catch (SQLException ex) {
762  throw new EamDbException("Error getting data source.", ex); // NON-NLS
763  } finally {
764  EamDbUtil.closeStatement(preparedStatement);
765  EamDbUtil.closeResultSet(resultSet);
767  }
768 
769  return eamDataSourceResult;
770  }
771 
781  @Override
782  public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws EamDbException {
783  if (correlationCase == null) {
784  throw new EamDbException("Correlation case is null");
785  }
786  try {
787  return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
788  } catch (CacheLoader.InvalidCacheLoadException ignored) {
789  //lambda valueloader returned a null value and cache can not store null values this is normal if the dataSource does not exist in the central repo yet
790  return null;
791  } catch (ExecutionException ex) {
792  throw new EamDbException("Error getting data source from central repository", ex);
793  }
794  }
795 
805  private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, int dataSourceId) throws EamDbException {
806  Connection conn = connect();
807 
808  CorrelationDataSource eamDataSourceResult = null;
809  PreparedStatement preparedStatement = null;
810  ResultSet resultSet = null;
811 
812  String sql = "SELECT * FROM data_sources WHERE id=? AND case_id=?"; // NON-NLS
813 
814  try {
815  preparedStatement = conn.prepareStatement(sql);
816  preparedStatement.setInt(1, dataSourceId);
817  preparedStatement.setInt(2, correlationCase.getID());
818  resultSet = preparedStatement.executeQuery();
819  if (resultSet.next()) {
820  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
821  }
822  if (eamDataSourceResult != null) {
823  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
824  }
825  } catch (SQLException ex) {
826  throw new EamDbException("Error getting data source.", ex); // NON-NLS
827  } finally {
828  EamDbUtil.closeStatement(preparedStatement);
829  EamDbUtil.closeResultSet(resultSet);
831  }
832 
833  return eamDataSourceResult;
834  }
835 
841  @Override
842  public List<CorrelationDataSource> getDataSources() throws EamDbException {
843  Connection conn = connect();
844 
845  List<CorrelationDataSource> dataSources = new ArrayList<>();
846  CorrelationDataSource eamDataSourceResult;
847  PreparedStatement preparedStatement = null;
848  ResultSet resultSet = null;
849 
850  String sql = "SELECT * FROM data_sources";
851 
852  try {
853  preparedStatement = conn.prepareStatement(sql);
854  resultSet = preparedStatement.executeQuery();
855  while (resultSet.next()) {
856  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
857  dataSources.add(eamDataSourceResult);
858  }
859  } catch (SQLException ex) {
860  throw new EamDbException("Error getting all data sources.", ex); // NON-NLS
861  } finally {
862  EamDbUtil.closeStatement(preparedStatement);
863  EamDbUtil.closeResultSet(resultSet);
865  }
866 
867  return dataSources;
868  }
869 
875  @Override
876  public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) throws EamDbException {
877  updateDataSourceStringValue(eamDataSource, "md5", eamDataSource.getMd5());
878  }
879 
885  @Override
886  public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) throws EamDbException {
887  updateDataSourceStringValue(eamDataSource, "sha1", eamDataSource.getSha1());
888  }
889 
896  @Override
897  public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) throws EamDbException {
898  updateDataSourceStringValue(eamDataSource, "sha256", eamDataSource.getSha256());
899  }
900 
908  private void updateDataSourceStringValue(CorrelationDataSource eamDataSource, String column, String value) throws EamDbException {
909  if (eamDataSource == null) {
910  throw new EamDbException("Correlation data source is null");
911  }
912 
913  Connection conn = connect();
914 
915  PreparedStatement preparedStatement = null;
916  String sql = "UPDATE data_sources "
917  + "SET " + column + "=? "
918  + "WHERE id=?";
919 
920  try {
921  preparedStatement = conn.prepareStatement(sql);
922 
923  preparedStatement.setString(1, value);
924  preparedStatement.setInt(2, eamDataSource.getID());
925 
926  preparedStatement.executeUpdate();
927  //update the case in the cache
928  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()), eamDataSource);
929  dataSourceCacheById.put(getDataSourceByIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getID()), eamDataSource);
930  } catch (SQLException ex) {
931  throw new EamDbException(String.format("Error updating data source (obj_id=%d).", eamDataSource.getDataSourceObjectID()), ex); // NON-NLS
932  } finally {
933  EamDbUtil.closeStatement(preparedStatement);
935  }
936  }
937 
946  @Override
947  public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws EamDbException {
948 
949  Connection conn = connect();
950 
951  PreparedStatement preparedStatement = null;
952 
953  String sql = "UPDATE data_sources SET name = ? WHERE id = ?";
954 
955  try {
956  preparedStatement = conn.prepareStatement(sql);
957  preparedStatement.setString(1, newName);
958  preparedStatement.setInt(2, eamDataSource.getID());
959  preparedStatement.executeUpdate();
960 
961  CorrelationDataSource updatedDataSource = new CorrelationDataSource(
962  eamDataSource.getCaseID(),
963  eamDataSource.getID(),
964  eamDataSource.getDeviceID(),
965  newName,
966  eamDataSource.getDataSourceObjectID(),
967  eamDataSource.getMd5(),
968  eamDataSource.getSha1(),
969  eamDataSource.getSha256());
970 
971  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getDataSourceObjectID()), updatedDataSource);
972  dataSourceCacheById.put(getDataSourceByIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getID()), updatedDataSource);
973  } catch (SQLException ex) {
974  throw new EamDbException("Error updating name of data source with ID " + eamDataSource.getDataSourceObjectID()
975  + " to " + newName, ex); // NON-NLS
976  } finally {
977  EamDbUtil.closeStatement(preparedStatement);
979  }
980  }
981 
988  @Override
989  public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws EamDbException {
990  checkAddArtifactInstanceNulls(eamArtifact);
991 
992  Connection conn = connect();
993 
994  PreparedStatement preparedStatement = null;
995 
996  // @@@ We should cache the case and data source IDs in memory
997  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
998  String sql
999  = "INSERT INTO "
1000  + tableName
1001  + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1002  + "VALUES (?, ?, ?, ?, ?, ?, ?) "
1003  + getConflictClause();
1004 
1005  try {
1006  preparedStatement = conn.prepareStatement(sql);
1007 
1008  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1009  preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
1010  preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1011  preparedStatement.setString(3, eamArtifact.getCorrelationValue());
1012  preparedStatement.setString(4, eamArtifact.getFilePath().toLowerCase());
1013  preparedStatement.setByte(5, eamArtifact.getKnownStatus().getFileKnownValue());
1014 
1015  if ("".equals(eamArtifact.getComment())) {
1016  preparedStatement.setNull(6, Types.INTEGER);
1017  } else {
1018  preparedStatement.setString(6, eamArtifact.getComment());
1019  }
1020  preparedStatement.setLong(7, eamArtifact.getFileObjectId());
1021 
1022  preparedStatement.executeUpdate();
1023  }
1024 
1025  } catch (SQLException ex) {
1026  throw new EamDbException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
1027  } finally {
1028  EamDbUtil.closeStatement(preparedStatement);
1029  EamDbUtil.closeConnection(conn);
1030  }
1031  }
1032 
1033  private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws EamDbException {
1034  if (eamArtifact == null) {
1035  throw new EamDbException("CorrelationAttribute is null");
1036  }
1037  if (eamArtifact.getCorrelationType() == null) {
1038  throw new EamDbException("Correlation type is null");
1039  }
1040  if (eamArtifact.getCorrelationValue() == null) {
1041  throw new EamDbException("Correlation value is null");
1042  }
1043  if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
1044  throw new EamDbException("Artifact value too long for central repository."
1045  + "\nCorrelationArtifact ID: " + eamArtifact.getID()
1046  + "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1047  + "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1048 
1049  }
1050  if (eamArtifact.getCorrelationCase() == null) {
1051  throw new EamDbException("CorrelationAttributeInstance case is null");
1052  }
1053  if (eamArtifact.getCorrelationDataSource() == null) {
1054  throw new EamDbException("CorrelationAttributeInstance data source is null");
1055  }
1056  if (eamArtifact.getKnownStatus() == null) {
1057  throw new EamDbException("CorrelationAttributeInstance known status is null");
1058  }
1059  }
1060 
1061  @Override
1062  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1063  if (value == null) {
1064  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null value");
1065  }
1066  return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
1067  }
1068 
1069  @Override
1070  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) throws EamDbException, CorrelationAttributeNormalizationException {
1071  if (aType == null) {
1072  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1073  }
1074  if (values == null || values.isEmpty()) {
1075  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1076  }
1077  return getArtifactInstances(prepareGetInstancesSql(aType, values), aType);
1078  }
1079 
1080  @Override
1081  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) throws EamDbException, CorrelationAttributeNormalizationException {
1082  if (aType == null) {
1083  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1084  }
1085  if (values == null || values.isEmpty()) {
1086  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1087  }
1088  if (caseIds == null || caseIds.isEmpty()) {
1089  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified cases");
1090  }
1091  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1092  String sql
1093  = " and "
1094  + tableName
1095  + ".case_id in ('";
1096  StringBuilder inValuesBuilder = new StringBuilder(prepareGetInstancesSql(aType, values));
1097  inValuesBuilder.append(sql);
1098  inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '")));
1099  inValuesBuilder.append("')");
1100  return getArtifactInstances(inValuesBuilder.toString(), aType);
1101  }
1102 
1115  private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) throws CorrelationAttributeNormalizationException {
1116  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1117  String sql
1118  = "SELECT "
1119  + tableName
1120  + ".id,"
1121  + tableName
1122  + ".value,"
1123  + tableName
1124  + ".file_obj_id,"
1125  + " 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, data_sources.datasource_obj_id, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM "
1126  + tableName
1127  + " LEFT JOIN cases ON "
1128  + tableName
1129  + ".case_id=cases.id"
1130  + " LEFT JOIN data_sources ON "
1131  + tableName
1132  + ".data_source_id=data_sources.id"
1133  + " WHERE value IN (";
1134  StringBuilder inValuesBuilder = new StringBuilder(sql);
1135  for (String value : values) {
1136  if (value != null) {
1137  inValuesBuilder.append("'");
1138  inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1139  inValuesBuilder.append("',");
1140  }
1141  }
1142  inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1143  inValuesBuilder.append(")");
1144  return inValuesBuilder.toString();
1145  }
1146 
1161  private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, EamDbException {
1162  Connection conn = connect();
1163  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1164  CorrelationAttributeInstance artifactInstance;
1165  PreparedStatement preparedStatement = null;
1166  ResultSet resultSet = null;
1167  try {
1168  preparedStatement = conn.prepareStatement(sql);
1169  resultSet = preparedStatement.executeQuery();
1170  while (resultSet.next()) {
1171  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1172  artifactInstances.add(artifactInstance);
1173  }
1174  } catch (SQLException ex) {
1175  throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1176  } finally {
1177  EamDbUtil.closeStatement(preparedStatement);
1178  EamDbUtil.closeResultSet(resultSet);
1179  EamDbUtil.closeConnection(conn);
1180  }
1181  return artifactInstances;
1182  }
1183 
1195  @Override
1196  public List<CorrelationAttributeInstance> getArtifactInstancesByPath(CorrelationAttributeInstance.Type aType, String filePath) throws EamDbException {
1197  if (aType == null) {
1198  throw new EamDbException("Correlation type is null");
1199  }
1200  if (filePath == null) {
1201  throw new EamDbException("Correlation value is null");
1202  }
1203  Connection conn = connect();
1204 
1205  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1206 
1207  CorrelationAttributeInstance artifactInstance;
1208  PreparedStatement preparedStatement = null;
1209  ResultSet resultSet = null;
1210 
1211  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1212  String sql
1213  = "SELECT "
1214  + tableName
1215  + ".id, "
1216  + tableName
1217  + ".value,"
1218  + tableName
1219  + ".file_obj_id,"
1220  + " 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, data_sources.datasource_obj_id, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM "
1221  + tableName
1222  + " LEFT JOIN cases ON "
1223  + tableName
1224  + ".case_id=cases.id"
1225  + " LEFT JOIN data_sources ON "
1226  + tableName
1227  + ".data_source_id=data_sources.id"
1228  + " WHERE file_path=?";
1229 
1230  try {
1231  preparedStatement = conn.prepareStatement(sql);
1232  preparedStatement.setString(1, filePath.toLowerCase());
1233  resultSet = preparedStatement.executeQuery();
1234  while (resultSet.next()) {
1235  try {
1236  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1237  artifactInstances.add(artifactInstance);
1238  } catch (CorrelationAttributeNormalizationException ex) {
1239  logger.log(Level.INFO, "Unable to get artifact instance from resultset.", ex);
1240  }
1241  }
1242  } catch (SQLException ex) {
1243  throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1244  } finally {
1245  EamDbUtil.closeStatement(preparedStatement);
1246  EamDbUtil.closeResultSet(resultSet);
1247  EamDbUtil.closeConnection(conn);
1248  }
1249 
1250  return artifactInstances;
1251  }
1252 
1263  @Override
1264  public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1265  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1266 
1267  Connection conn = connect();
1268 
1269  Long instanceCount = 0L;
1270  PreparedStatement preparedStatement = null;
1271  ResultSet resultSet = null;
1272 
1273  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1274  String sql
1275  = "SELECT count(*) FROM "
1276  + tableName
1277  + " WHERE value=?";
1278 
1279  try {
1280  preparedStatement = conn.prepareStatement(sql);
1281  preparedStatement.setString(1, normalizedValue);
1282  resultSet = preparedStatement.executeQuery();
1283  resultSet.next();
1284  instanceCount = resultSet.getLong(1);
1285  } catch (SQLException ex) {
1286  throw new EamDbException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1287  } finally {
1288  EamDbUtil.closeStatement(preparedStatement);
1289  EamDbUtil.closeResultSet(resultSet);
1290  EamDbUtil.closeConnection(conn);
1291  }
1292 
1293  return instanceCount;
1294  }
1295 
1296  @Override
1297  public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws EamDbException, CorrelationAttributeNormalizationException {
1298  if (corAttr == null) {
1299  throw new EamDbException("CorrelationAttribute is null");
1300  }
1301  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1302  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1303  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1304  return commonalityPercentage.intValue();
1305  }
1306 
1317  @Override
1318  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1319  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1320 
1321  Connection conn = connect();
1322 
1323  Long instanceCount = 0L;
1324  PreparedStatement preparedStatement = null;
1325  ResultSet resultSet = null;
1326 
1327  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1328  String sql
1329  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1330  + tableName
1331  + " WHERE value=?) AS "
1332  + tableName
1333  + "_distinct_case_data_source_tuple";
1334 
1335  try {
1336  preparedStatement = conn.prepareStatement(sql);
1337  preparedStatement.setString(1, normalizedValue);
1338  resultSet = preparedStatement.executeQuery();
1339  resultSet.next();
1340  instanceCount = resultSet.getLong(1);
1341  } catch (SQLException ex) {
1342  throw new EamDbException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1343  } finally {
1344  EamDbUtil.closeStatement(preparedStatement);
1345  EamDbUtil.closeResultSet(resultSet);
1346  EamDbUtil.closeConnection(conn);
1347  }
1348 
1349  return instanceCount;
1350  }
1351 
1352  @Override
1353  public Long getCountUniqueDataSources() throws EamDbException {
1354  Connection conn = connect();
1355 
1356  Long instanceCount = 0L;
1357  PreparedStatement preparedStatement = null;
1358  ResultSet resultSet = null;
1359 
1360  String stmt = "SELECT count(*) FROM data_sources";
1361 
1362  try {
1363  preparedStatement = conn.prepareStatement(stmt);
1364  resultSet = preparedStatement.executeQuery();
1365  resultSet.next();
1366  instanceCount = resultSet.getLong(1);
1367  } catch (SQLException ex) {
1368  throw new EamDbException("Error counting data sources.", ex); // NON-NLS
1369  } finally {
1370  EamDbUtil.closeStatement(preparedStatement);
1371  EamDbUtil.closeResultSet(resultSet);
1372  EamDbUtil.closeConnection(conn);
1373  }
1374 
1375  return instanceCount;
1376  }
1377 
1389  @Override
1390  public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws EamDbException {
1391  Connection conn = connect();
1392 
1393  Long instanceCount = 0L;
1394  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1395  PreparedStatement preparedStatement = null;
1396  ResultSet resultSet = null;
1397 
1398  //Create query to get count of all instances in the database for the specified case specific data source
1399  String sql = "SELECT 0 ";
1400 
1401  for (CorrelationAttributeInstance.Type type : artifactTypes) {
1402  String table_name = EamDbUtil.correlationTypeToInstanceTableName(type);
1403  sql
1404  += "+ (SELECT count(*) FROM "
1405  + table_name
1406  + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1407  }
1408  try {
1409  preparedStatement = conn.prepareStatement(sql);
1410 
1411  resultSet = preparedStatement.executeQuery();
1412  resultSet.next();
1413  instanceCount = resultSet.getLong(1);
1414  } catch (SQLException ex) {
1415  throw new EamDbException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1416  } finally {
1417  EamDbUtil.closeStatement(preparedStatement);
1418  EamDbUtil.closeResultSet(resultSet);
1419  EamDbUtil.closeConnection(conn);
1420  }
1421 
1422  return instanceCount;
1423  }
1424 
1432  @Override
1433  public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws EamDbException {
1434 
1435  if (eamArtifact.getCorrelationType() == null) {
1436  throw new EamDbException("Correlation type is null");
1437  }
1438 
1439  synchronized (bulkArtifacts) {
1440  bulkArtifacts.get(EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1441  bulkArtifactsCount++;
1442 
1443  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1444  commitAttributeInstancesBulk();
1445  }
1446  }
1447  }
1448 
1454  protected abstract String getConflictClause();
1455 
1460  @Override
1461  public void commitAttributeInstancesBulk() throws EamDbException {
1462  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1463 
1464  Connection conn = connect();
1465  PreparedStatement bulkPs = null;
1466 
1467  try {
1468  synchronized (bulkArtifacts) {
1469  if (bulkArtifactsCount == 0) {
1470  return;
1471  }
1472 
1473  for (String tableName : bulkArtifacts.keySet()) {
1474 
1475  String sql
1476  = "INSERT INTO "
1477  + tableName
1478  + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1479  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1480  + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1481  + getConflictClause();
1482 
1483  bulkPs = conn.prepareStatement(sql);
1484 
1485  Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1486  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1487 
1488  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1489 
1490  if (eamArtifact.getCorrelationCase() == null) {
1491  throw new EamDbException("CorrelationAttributeInstance case is null for: "
1492  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1493  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1494  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1495  }
1496  if (eamArtifact.getCorrelationDataSource() == null) {
1497  throw new EamDbException("CorrelationAttributeInstance data source is null for: "
1498  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1499  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1500  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1501  }
1502  if (eamArtifact.getKnownStatus() == null) {
1503  throw new EamDbException("CorrelationAttributeInstance known status is null for: "
1504  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1505  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1506  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1507  + "\n\tEam Instance: "
1508  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1509  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1510  }
1511 
1512  if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1513  bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1514  bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1515  bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1516  bulkPs.setString(4, eamArtifact.getCorrelationValue());
1517  bulkPs.setString(5, eamArtifact.getFilePath());
1518  bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1519  if ("".equals(eamArtifact.getComment())) {
1520  bulkPs.setNull(7, Types.INTEGER);
1521  } else {
1522  bulkPs.setString(7, eamArtifact.getComment());
1523  }
1524  bulkPs.setLong(8, eamArtifact.getFileObjectId());
1525  bulkPs.addBatch();
1526  } else {
1527  logger.log(Level.WARNING, ("Artifact value too long for central repository."
1528  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1529  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1530  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1531  + "\n\tEam Instance: "
1532  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1533  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1534  + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1535  }
1536  }
1537 
1538  }
1539 
1540  bulkPs.executeBatch();
1541  bulkArtifacts.get(tableName).clear();
1542  }
1543 
1544  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
1545  HealthMonitor.submitTimingMetric(timingMetric);
1546 
1547  // Reset state
1548  bulkArtifactsCount = 0;
1549  }
1550  } catch (SQLException ex) {
1551  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
1552  } finally {
1553  EamDbUtil.closeStatement(bulkPs);
1554  EamDbUtil.closeConnection(conn);
1555  }
1556  }
1557 
1561  @Override
1562  public void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException {
1563  if (cases == null) {
1564  throw new EamDbException("cases argument is null");
1565  }
1566 
1567  if (cases.isEmpty()) {
1568  return;
1569  }
1570 
1571  Connection conn = connect();
1572 
1573  int counter = 0;
1574  PreparedStatement bulkPs = null;
1575  try {
1576  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1577  + "examiner_name, examiner_email, examiner_phone, notes) "
1578  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1579  + getConflictClause();
1580  bulkPs = conn.prepareStatement(sql);
1581 
1582  for (CorrelationCase eamCase : cases) {
1583  bulkPs.setString(1, eamCase.getCaseUUID());
1584  if (null == eamCase.getOrg()) {
1585  bulkPs.setNull(2, Types.INTEGER);
1586  } else {
1587  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1588  }
1589  bulkPs.setString(3, eamCase.getDisplayName());
1590  bulkPs.setString(4, eamCase.getCreationDate());
1591 
1592  if ("".equals(eamCase.getCaseNumber())) {
1593  bulkPs.setNull(5, Types.INTEGER);
1594  } else {
1595  bulkPs.setString(5, eamCase.getCaseNumber());
1596  }
1597  if ("".equals(eamCase.getExaminerName())) {
1598  bulkPs.setNull(6, Types.INTEGER);
1599  } else {
1600  bulkPs.setString(6, eamCase.getExaminerName());
1601  }
1602  if ("".equals(eamCase.getExaminerEmail())) {
1603  bulkPs.setNull(7, Types.INTEGER);
1604  } else {
1605  bulkPs.setString(7, eamCase.getExaminerEmail());
1606  }
1607  if ("".equals(eamCase.getExaminerPhone())) {
1608  bulkPs.setNull(8, Types.INTEGER);
1609  } else {
1610  bulkPs.setString(8, eamCase.getExaminerPhone());
1611  }
1612  if ("".equals(eamCase.getNotes())) {
1613  bulkPs.setNull(9, Types.INTEGER);
1614  } else {
1615  bulkPs.setString(9, eamCase.getNotes());
1616  }
1617 
1618  bulkPs.addBatch();
1619 
1620  counter++;
1621 
1622  // limit a batch's max size to bulkArtifactsThreshold
1623  if (counter >= bulkArtifactsThreshold) {
1624  bulkPs.executeBatch();
1625  counter = 0;
1626  }
1627  }
1628  // send the remaining batch records
1629  bulkPs.executeBatch();
1630  } catch (SQLException ex) {
1631  throw new EamDbException("Error inserting bulk cases.", ex); // NON-NLS
1632  } finally {
1633  EamDbUtil.closeStatement(bulkPs);
1634  EamDbUtil.closeConnection(conn);
1635  }
1636  }
1637 
1647  @Override
1648  public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws EamDbException {
1649 
1650  if (eamArtifact == null) {
1651  throw new EamDbException("CorrelationAttributeInstance is null");
1652  }
1653  if (eamArtifact.getCorrelationCase() == null) {
1654  throw new EamDbException("Correlation case is null");
1655  }
1656  if (eamArtifact.getCorrelationDataSource() == null) {
1657  throw new EamDbException("Correlation data source is null");
1658  }
1659  Connection conn = connect();
1660  PreparedStatement preparedQuery = null;
1661  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1662  String sqlUpdate
1663  = "UPDATE "
1664  + tableName
1665  + " SET comment=? "
1666  + "WHERE case_id=? "
1667  + "AND data_source_id=? "
1668  + "AND value=? "
1669  + "AND file_path=?";
1670 
1671  try {
1672  preparedQuery = conn.prepareStatement(sqlUpdate);
1673  preparedQuery.setString(1, eamArtifact.getComment());
1674  preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1675  preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1676  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1677  preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1678  preparedQuery.executeUpdate();
1679  } catch (SQLException ex) {
1680  throw new EamDbException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1681  } finally {
1682  EamDbUtil.closeStatement(preparedQuery);
1683  EamDbUtil.closeConnection(conn);
1684  }
1685  }
1686 
1701  @Override
1702  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1703  CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException {
1704 
1705  if (correlationCase == null) {
1706  throw new EamDbException("Correlation case is null");
1707  }
1708 
1709  Connection conn = connect();
1710 
1711  PreparedStatement preparedStatement = null;
1712  ResultSet resultSet = null;
1713  CorrelationAttributeInstance correlationAttributeInstance = null;
1714 
1715  try {
1716 
1717  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1718  String sql
1719  = "SELECT id, value, file_path, known_status, comment FROM "
1720  + tableName
1721  + " WHERE case_id=?"
1722  + " AND file_obj_id=?";
1723 
1724  preparedStatement = conn.prepareStatement(sql);
1725  preparedStatement.setInt(1, correlationCase.getID());
1726  preparedStatement.setInt(2, (int) objectID);
1727  resultSet = preparedStatement.executeQuery();
1728  if (resultSet.next()) {
1729  int instanceId = resultSet.getInt(1);
1730  String value = resultSet.getString(2);
1731  String filePath = resultSet.getString(3);
1732  int knownStatus = resultSet.getInt(4);
1733  String comment = resultSet.getString(5);
1734 
1735  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1736  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1737  }
1738  } catch (SQLException ex) {
1739  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1740  } finally {
1741  EamDbUtil.closeStatement(preparedStatement);
1742  EamDbUtil.closeResultSet(resultSet);
1743  EamDbUtil.closeConnection(conn);
1744  }
1745 
1746  return correlationAttributeInstance;
1747  }
1748 
1763  @Override
1764  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1765  CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException, CorrelationAttributeNormalizationException {
1766 
1767  if (correlationCase == null) {
1768  throw new EamDbException("Correlation case is null");
1769  }
1770  if (correlationDataSource == null) {
1771  throw new EamDbException("Correlation data source is null");
1772  }
1773  if (filePath == null) {
1774  throw new EamDbException("Correlation file path is null");
1775  }
1776 
1777  Connection conn = connect();
1778 
1779  PreparedStatement preparedStatement = null;
1780  ResultSet resultSet = null;
1781  CorrelationAttributeInstance correlationAttributeInstance = null;
1782 
1783  try {
1784  String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1785 
1786  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1787  String sql
1788  = "SELECT id, known_status, comment FROM "
1789  + tableName
1790  + " WHERE case_id=?"
1791  + " AND data_source_id=?"
1792  + " AND value=?"
1793  + " AND file_path=?";
1794 
1795  preparedStatement = conn.prepareStatement(sql);
1796  preparedStatement.setInt(1, correlationCase.getID());
1797  preparedStatement.setInt(2, correlationDataSource.getID());
1798  preparedStatement.setString(3, normalizedValue);
1799  preparedStatement.setString(4, filePath.toLowerCase());
1800  resultSet = preparedStatement.executeQuery();
1801  if (resultSet.next()) {
1802  int instanceId = resultSet.getInt(1);
1803  int knownStatus = resultSet.getInt(2);
1804  String comment = resultSet.getString(3);
1805  //null objectId used because we only fall back to using this method when objectID was not available
1806  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1807  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
1808  }
1809  } catch (SQLException ex) {
1810  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1811  } finally {
1812  EamDbUtil.closeStatement(preparedStatement);
1813  EamDbUtil.closeResultSet(resultSet);
1814  EamDbUtil.closeConnection(conn);
1815  }
1816 
1817  return correlationAttributeInstance;
1818  }
1819 
1830  @Override
1831  public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
1832  if (eamArtifact == null) {
1833  throw new EamDbException("CorrelationAttribute is null");
1834  }
1835  if (knownStatus == null) {
1836  throw new EamDbException("Known status is null");
1837  }
1838 
1839  if (eamArtifact.getCorrelationCase() == null) {
1840  throw new EamDbException("Correlation case is null");
1841  }
1842  if (eamArtifact.getCorrelationDataSource() == null) {
1843  throw new EamDbException("Correlation data source is null");
1844  }
1845 
1846  Connection conn = connect();
1847 
1848  PreparedStatement preparedUpdate = null;
1849  PreparedStatement preparedQuery = null;
1850  ResultSet resultSet = null;
1851 
1852  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1853 
1854  String sqlQuery
1855  = "SELECT id FROM "
1856  + tableName
1857  + " WHERE case_id=? "
1858  + "AND data_source_id=? "
1859  + "AND value=? "
1860  + "AND file_path=?";
1861 
1862  String sqlUpdate
1863  = "UPDATE "
1864  + tableName
1865  + " SET known_status=?, comment=? "
1866  + "WHERE id=?";
1867 
1868  try {
1869  preparedQuery = conn.prepareStatement(sqlQuery);
1870  preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
1871  preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1872  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
1873  preparedQuery.setString(4, eamArtifact.getFilePath());
1874  resultSet = preparedQuery.executeQuery();
1875  if (resultSet.next()) {
1876  int instance_id = resultSet.getInt("id");
1877  preparedUpdate = conn.prepareStatement(sqlUpdate);
1878 
1879  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
1880  // NOTE: if the user tags the same instance as BAD multiple times,
1881  // the comment from the most recent tagging is the one that will
1882  // prevail in the DB.
1883  if ("".equals(eamArtifact.getComment())) {
1884  preparedUpdate.setNull(2, Types.INTEGER);
1885  } else {
1886  preparedUpdate.setString(2, eamArtifact.getComment());
1887  }
1888  preparedUpdate.setInt(3, instance_id);
1889 
1890  preparedUpdate.executeUpdate();
1891  } else {
1892  // In this case, the user is tagging something that isn't in the database,
1893  // which means the case and/or datasource may also not be in the database.
1894  // We could improve effiency by keeping a list of all datasources and cases
1895  // in the database, but we don't expect the user to be tagging large numbers
1896  // of items (that didn't have the CE ingest module run on them) at once.
1897  CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
1898  if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
1899  newDataSource(eamArtifact.getCorrelationDataSource());
1900  }
1901  eamArtifact.setKnownStatus(knownStatus);
1902  addArtifactInstance(eamArtifact);
1903  }
1904 
1905  } catch (SQLException ex) {
1906  throw new EamDbException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
1907  } finally {
1908  EamDbUtil.closeStatement(preparedUpdate);
1909  EamDbUtil.closeStatement(preparedQuery);
1910  EamDbUtil.closeResultSet(resultSet);
1911  EamDbUtil.closeConnection(conn);
1912  }
1913  }
1914 
1924  @Override
1925  public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1926  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1927 
1928  Connection conn = connect();
1929 
1930  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1931 
1932  CorrelationAttributeInstance artifactInstance;
1933  PreparedStatement preparedStatement = null;
1934  ResultSet resultSet = null;
1935 
1936  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1937  String sql
1938  = "SELECT "
1939  + tableName
1940  + ".id, "
1941  + tableName
1942  + ".value, "
1943  + tableName
1944  + ".file_obj_id,"
1945  + "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, data_sources.datasource_obj_id, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM "
1946  + tableName
1947  + " LEFT JOIN cases ON "
1948  + tableName
1949  + ".case_id=cases.id"
1950  + " LEFT JOIN data_sources ON "
1951  + tableName
1952  + ".data_source_id=data_sources.id"
1953  + " WHERE value=? AND known_status=?";
1954 
1955  try {
1956  preparedStatement = conn.prepareStatement(sql);
1957  preparedStatement.setString(1, normalizedValue);
1958  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1959  resultSet = preparedStatement.executeQuery();
1960  while (resultSet.next()) {
1961  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1962  artifactInstances.add(artifactInstance);
1963  }
1964  } catch (SQLException ex) {
1965  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1966  } finally {
1967  EamDbUtil.closeStatement(preparedStatement);
1968  EamDbUtil.closeResultSet(resultSet);
1969  EamDbUtil.closeConnection(conn);
1970  }
1971 
1972  return artifactInstances;
1973  }
1974 
1986  @Override
1987  public List<CorrelationAttributeInstance> getArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType) throws EamDbException {
1988  if (aType == null) {
1989  throw new EamDbException("Correlation type is null");
1990  }
1991 
1992  Connection conn = connect();
1993 
1994  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1995 
1996  CorrelationAttributeInstance artifactInstance;
1997  PreparedStatement preparedStatement = null;
1998  ResultSet resultSet = null;
1999 
2000  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
2001  String sql
2002  = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, id, value, file_obj_id, data_sources.datasource_obj_id, data_sources.md5, data_sources.sha1, data_sources.sha256 FROM "
2003  + tableName
2004  + " LEFT JOIN cases ON "
2005  + tableName
2006  + ".case_id=cases.id"
2007  + " LEFT JOIN data_sources ON "
2008  + tableName
2009  + ".data_source_id=data_sources.id"
2010  + " WHERE known_status=?"
2011  + " GROUP BY "
2012  + tableName
2013  + ".value";
2014 
2015  try {
2016  preparedStatement = conn.prepareStatement(sql);
2017  preparedStatement.setByte(1, TskData.FileKnown.BAD.getFileKnownValue());
2018  resultSet = preparedStatement.executeQuery();
2019  while (resultSet.next()) {
2020  try {
2021  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
2022  artifactInstances.add(artifactInstance);
2023  } catch (CorrelationAttributeNormalizationException ex) {
2024  logger.log(Level.INFO, "Unable to get artifact instance from resultset.", ex);
2025  }
2026  }
2027  } catch (SQLException ex) {
2028  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
2029  } finally {
2030  EamDbUtil.closeStatement(preparedStatement);
2031  EamDbUtil.closeResultSet(resultSet);
2032  EamDbUtil.closeConnection(conn);
2033  }
2034 
2035  return artifactInstances;
2036  }
2037 
2046  @Override
2047  public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
2048 
2049  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2050 
2051  Connection conn = connect();
2052 
2053  Long badInstances = 0L;
2054  PreparedStatement preparedStatement = null;
2055  ResultSet resultSet = null;
2056 
2057  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
2058  String sql
2059  = "SELECT count(*) FROM "
2060  + tableName
2061  + " WHERE value=? AND known_status=?";
2062 
2063  try {
2064  preparedStatement = conn.prepareStatement(sql);
2065  preparedStatement.setString(1, normalizedValue);
2066  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2067  resultSet = preparedStatement.executeQuery();
2068  resultSet.next();
2069  badInstances = resultSet.getLong(1);
2070  } catch (SQLException ex) {
2071  throw new EamDbException("Error getting count of notable artifact instances.", ex); // NON-NLS
2072  } finally {
2073  EamDbUtil.closeStatement(preparedStatement);
2074  EamDbUtil.closeResultSet(resultSet);
2075  EamDbUtil.closeConnection(conn);
2076  }
2077 
2078  return badInstances;
2079  }
2080 
2093  @Override
2094  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
2095 
2096  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2097 
2098  Connection conn = connect();
2099 
2100  Collection<String> caseNames = new LinkedHashSet<>();
2101 
2102  PreparedStatement preparedStatement = null;
2103  ResultSet resultSet = null;
2104 
2105  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
2106  String sql
2107  = "SELECT DISTINCT case_name FROM "
2108  + tableName
2109  + " INNER JOIN cases ON "
2110  + tableName
2111  + ".case_id=cases.id WHERE "
2112  + tableName
2113  + ".value=? AND "
2114  + tableName
2115  + ".known_status=?";
2116 
2117  try {
2118  preparedStatement = conn.prepareStatement(sql);
2119  preparedStatement.setString(1, normalizedValue);
2120  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2121  resultSet = preparedStatement.executeQuery();
2122  while (resultSet.next()) {
2123  caseNames.add(resultSet.getString("case_name"));
2124  }
2125  } catch (SQLException ex) {
2126  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
2127  } finally {
2128  EamDbUtil.closeStatement(preparedStatement);
2129  EamDbUtil.closeResultSet(resultSet);
2130  EamDbUtil.closeConnection(conn);
2131  }
2132 
2133  return caseNames.stream().collect(Collectors.toList());
2134  }
2135 
2143  @Override
2144  public void deleteReferenceSet(int referenceSetID) throws EamDbException {
2145  deleteReferenceSetEntries(referenceSetID);
2146  deleteReferenceSetEntry(referenceSetID);
2147  }
2148 
2156  private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException {
2157  Connection conn = connect();
2158 
2159  PreparedStatement preparedStatement = null;
2160  String sql = "DELETE FROM reference_sets WHERE id=?";
2161 
2162  try {
2163  preparedStatement = conn.prepareStatement(sql);
2164  preparedStatement.setInt(1, referenceSetID);
2165  preparedStatement.executeUpdate();
2166  } catch (SQLException ex) {
2167  throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2168  } finally {
2169  EamDbUtil.closeStatement(preparedStatement);
2170  EamDbUtil.closeConnection(conn);
2171  }
2172  }
2173 
2182  private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException {
2183  Connection conn = connect();
2184 
2185  PreparedStatement preparedStatement = null;
2186  String sql = "DELETE FROM %s WHERE reference_set_id=?";
2187 
2188  // When other reference types are added, this will need to loop over all the tables
2189  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2190 
2191  try {
2192  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2193  preparedStatement.setInt(1, referenceSetID);
2194  preparedStatement.executeUpdate();
2195  } catch (SQLException ex) {
2196  throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2197  } finally {
2198  EamDbUtil.closeStatement(preparedStatement);
2199  EamDbUtil.closeConnection(conn);
2200  }
2201  }
2202 
2216  @Override
2217  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException {
2218  EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID);
2219  if (refSet == null) {
2220  return false;
2221  }
2222 
2223  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2224  }
2225 
2237  @Override
2238  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException, CorrelationAttributeNormalizationException {
2239  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2240  }
2241 
2251  @Override
2252  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException, CorrelationAttributeNormalizationException {
2253 
2254  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2255 
2256  Connection conn = connect();
2257 
2258  Long matchingInstances = 0L;
2259  PreparedStatement preparedStatement = null;
2260  ResultSet resultSet = null;
2261  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2262 
2263  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2264 
2265  try {
2266  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2267  preparedStatement.setString(1, normalizeValued);
2268  preparedStatement.setInt(2, referenceSetID);
2269  resultSet = preparedStatement.executeQuery();
2270  resultSet.next();
2271  matchingInstances = resultSet.getLong(1);
2272  } catch (SQLException ex) {
2273  throw new EamDbException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2274  } finally {
2275  EamDbUtil.closeStatement(preparedStatement);
2276  EamDbUtil.closeResultSet(resultSet);
2277  EamDbUtil.closeConnection(conn);
2278  }
2279 
2280  return 0 < matchingInstances;
2281  }
2282 
2291  @Override
2292  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
2293 
2294  //this should be done here so that we can be certain that aType and value are valid before we proceed
2295  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2296 
2297  // TEMP: Only support file correlation type
2298  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2299  return false;
2300  }
2301 
2302  Connection conn = connect();
2303 
2304  Long badInstances = 0L;
2305  PreparedStatement preparedStatement = null;
2306  ResultSet resultSet = null;
2307  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2308 
2309  try {
2310  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2311  preparedStatement.setString(1, normalizeValued);
2312  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2313  resultSet = preparedStatement.executeQuery();
2314  resultSet.next();
2315  badInstances = resultSet.getLong(1);
2316  } catch (SQLException ex) {
2317  throw new EamDbException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2318  } finally {
2319  EamDbUtil.closeStatement(preparedStatement);
2320  EamDbUtil.closeResultSet(resultSet);
2321  EamDbUtil.closeConnection(conn);
2322  }
2323 
2324  return 0 < badInstances;
2325  }
2326 
2335  @Override
2336  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
2337  if (type == null) {
2338  throw new EamDbException("Correlation type is null");
2339  }
2340 
2341  if (instanceTableCallback == null) {
2342  throw new EamDbException("Callback interface is null");
2343  }
2344 
2345  Connection conn = connect();
2346  PreparedStatement preparedStatement = null;
2347  ResultSet resultSet = null;
2348  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2349  StringBuilder sql = new StringBuilder();
2350  sql.append("select * from ");
2351  sql.append(tableName);
2352 
2353  try {
2354  preparedStatement = conn.prepareStatement(sql.toString());
2355  resultSet = preparedStatement.executeQuery();
2356  instanceTableCallback.process(resultSet);
2357  } catch (SQLException ex) {
2358  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2359  } finally {
2360  EamDbUtil.closeStatement(preparedStatement);
2361  EamDbUtil.closeResultSet(resultSet);
2362  EamDbUtil.closeConnection(conn);
2363  }
2364  }
2365 
2375  @Override
2376  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException {
2377  if (type == null) {
2378  throw new EamDbException("Correlation type is null");
2379  }
2380 
2381  if (instanceTableCallback == null) {
2382  throw new EamDbException("Callback interface is null");
2383  }
2384 
2385  if (whereClause == null) {
2386  throw new EamDbException("Where clause is null");
2387  }
2388 
2389  Connection conn = connect();
2390  PreparedStatement preparedStatement = null;
2391  ResultSet resultSet = null;
2392  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2393  StringBuilder sql = new StringBuilder(300);
2394  sql.append("select * from ")
2395  .append(tableName)
2396  .append(" WHERE ")
2397  .append(whereClause);
2398 
2399  try {
2400  preparedStatement = conn.prepareStatement(sql.toString());
2401  resultSet = preparedStatement.executeQuery();
2402  instanceTableCallback.process(resultSet);
2403  } catch (SQLException ex) {
2404  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2405  } finally {
2406  EamDbUtil.closeStatement(preparedStatement);
2407  EamDbUtil.closeResultSet(resultSet);
2408  EamDbUtil.closeConnection(conn);
2409  }
2410  }
2411 
2412  @Override
2413  public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
2414  if (eamOrg == null) {
2415  throw new EamDbException("EamOrganization is null");
2416  } else if (eamOrg.getOrgID() != -1) {
2417  throw new EamDbException("EamOrganization already has an ID");
2418  }
2419 
2420  Connection conn = connect();
2421  ResultSet generatedKeys = null;
2422  PreparedStatement preparedStatement = null;
2423  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2424  + getConflictClause();
2425 
2426  try {
2427  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2428  preparedStatement.setString(1, eamOrg.getName());
2429  preparedStatement.setString(2, eamOrg.getPocName());
2430  preparedStatement.setString(3, eamOrg.getPocEmail());
2431  preparedStatement.setString(4, eamOrg.getPocPhone());
2432 
2433  preparedStatement.executeUpdate();
2434  generatedKeys = preparedStatement.getGeneratedKeys();
2435  if (generatedKeys.next()) {
2436  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2437  return eamOrg;
2438  } else {
2439  throw new SQLException("Creating user failed, no ID obtained.");
2440  }
2441  } catch (SQLException ex) {
2442  throw new EamDbException("Error inserting new organization.", ex); // NON-NLS
2443  } finally {
2444  EamDbUtil.closeStatement(preparedStatement);
2445  EamDbUtil.closeResultSet(generatedKeys);
2446  EamDbUtil.closeConnection(conn);
2447  }
2448  }
2449 
2457  @Override
2458  public List<EamOrganization> getOrganizations() throws EamDbException {
2459  Connection conn = connect();
2460 
2461  List<EamOrganization> orgs = new ArrayList<>();
2462  PreparedStatement preparedStatement = null;
2463  ResultSet resultSet = null;
2464  String sql = "SELECT * FROM organizations";
2465 
2466  try {
2467  preparedStatement = conn.prepareStatement(sql);
2468  resultSet = preparedStatement.executeQuery();
2469  while (resultSet.next()) {
2470  orgs.add(getEamOrganizationFromResultSet(resultSet));
2471  }
2472  return orgs;
2473 
2474  } catch (SQLException ex) {
2475  throw new EamDbException("Error getting all organizations.", ex); // NON-NLS
2476  } finally {
2477  EamDbUtil.closeStatement(preparedStatement);
2478  EamDbUtil.closeResultSet(resultSet);
2479  EamDbUtil.closeConnection(conn);
2480  }
2481  }
2482 
2492  @Override
2493  public EamOrganization getOrganizationByID(int orgID) throws EamDbException {
2494  Connection conn = connect();
2495 
2496  PreparedStatement preparedStatement = null;
2497  ResultSet resultSet = null;
2498  String sql = "SELECT * FROM organizations WHERE id=?";
2499 
2500  try {
2501  preparedStatement = conn.prepareStatement(sql);
2502  preparedStatement.setInt(1, orgID);
2503  resultSet = preparedStatement.executeQuery();
2504  resultSet.next();
2505  return getEamOrganizationFromResultSet(resultSet);
2506 
2507  } catch (SQLException ex) {
2508  throw new EamDbException("Error getting organization by id.", ex); // NON-NLS
2509  } finally {
2510  EamDbUtil.closeStatement(preparedStatement);
2511  EamDbUtil.closeResultSet(resultSet);
2512  EamDbUtil.closeConnection(conn);
2513  }
2514  }
2515 
2525  @Override
2526  public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException {
2527 
2528  EamGlobalSet globalSet = getReferenceSetByID(referenceSetID);
2529  if (globalSet == null) {
2530  throw new EamDbException("Reference set with ID " + referenceSetID + " not found");
2531  }
2532  return (getOrganizationByID(globalSet.getOrgID()));
2533  }
2534 
2542  private void testArgument(EamOrganization org) throws EamDbException {
2543  if (org == null) {
2544  throw new EamDbException("EamOrganization is null");
2545  } else if (org.getOrgID() == -1) {
2546  throw new EamDbException("Organization has -1 row ID");
2547  }
2548  }
2549 
2558  @Override
2559  public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException {
2560  testArgument(updatedOrganization);
2561 
2562  Connection conn = connect();
2563  PreparedStatement preparedStatement = null;
2564  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2565  try {
2566  preparedStatement = conn.prepareStatement(sql);
2567  preparedStatement.setString(1, updatedOrganization.getName());
2568  preparedStatement.setString(2, updatedOrganization.getPocName());
2569  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2570  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2571  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2572  preparedStatement.executeUpdate();
2573  } catch (SQLException ex) {
2574  throw new EamDbException("Error updating organization.", ex); // NON-NLS
2575  } finally {
2576  EamDbUtil.closeStatement(preparedStatement);
2577  EamDbUtil.closeConnection(conn);
2578  }
2579  }
2580 
2581  @Override
2582  public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException {
2583  testArgument(organizationToDelete);
2584 
2585  Connection conn = connect();
2586  PreparedStatement checkIfUsedStatement = null;
2587  ResultSet resultSet = null;
2588  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2589  PreparedStatement deleteOrgStatement = null;
2590  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2591  try {
2592  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2593  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2594  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2595  resultSet = checkIfUsedStatement.executeQuery();
2596  resultSet.next();
2597  if (resultSet.getLong(1) > 0) {
2598  throw new EamDbException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2599  }
2600  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2601  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2602  deleteOrgStatement.executeUpdate();
2603  } catch (SQLException ex) {
2604  throw new EamDbException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2605  } finally {
2606  EamDbUtil.closeStatement(checkIfUsedStatement);
2607  EamDbUtil.closeStatement(deleteOrgStatement);
2608  EamDbUtil.closeResultSet(resultSet);
2609  EamDbUtil.closeConnection(conn);
2610  }
2611  }
2612 
2622  @Override
2623  public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException {
2624  if (eamGlobalSet == null) {
2625  throw new EamDbException("EamGlobalSet is null");
2626  }
2627 
2628  if (eamGlobalSet.getFileKnownStatus() == null) {
2629  throw new EamDbException("File known status on the EamGlobalSet is null");
2630  }
2631 
2632  if (eamGlobalSet.getType() == null) {
2633  throw new EamDbException("Type on the EamGlobalSet is null");
2634  }
2635 
2636  Connection conn = connect();
2637 
2638  PreparedStatement preparedStatement1 = null;
2639  PreparedStatement preparedStatement2 = null;
2640  ResultSet resultSet = null;
2641  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2642  + getConflictClause();
2643  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2644 
2645  try {
2646  preparedStatement1 = conn.prepareStatement(sql1);
2647  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2648  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2649  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2650  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2651  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2652  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2653  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2654 
2655  preparedStatement1.executeUpdate();
2656 
2657  preparedStatement2 = conn.prepareStatement(sql2);
2658  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2659  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2660  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2661  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2662 
2663  resultSet = preparedStatement2.executeQuery();
2664  resultSet.next();
2665  return resultSet.getInt("id");
2666 
2667  } catch (SQLException ex) {
2668  throw new EamDbException("Error inserting new global set.", ex); // NON-NLS
2669  } finally {
2670  EamDbUtil.closeStatement(preparedStatement1);
2671  EamDbUtil.closeStatement(preparedStatement2);
2672  EamDbUtil.closeResultSet(resultSet);
2673  EamDbUtil.closeConnection(conn);
2674  }
2675  }
2676 
2686  @Override
2687  public EamGlobalSet getReferenceSetByID(int referenceSetID) throws EamDbException {
2688  Connection conn = connect();
2689 
2690  PreparedStatement preparedStatement1 = null;
2691  ResultSet resultSet = null;
2692  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2693 
2694  try {
2695  preparedStatement1 = conn.prepareStatement(sql1);
2696  preparedStatement1.setInt(1, referenceSetID);
2697  resultSet = preparedStatement1.executeQuery();
2698  if (resultSet.next()) {
2699  return getEamGlobalSetFromResultSet(resultSet);
2700  } else {
2701  return null;
2702  }
2703 
2704  } catch (SQLException ex) {
2705  throw new EamDbException("Error getting reference set by id.", ex); // NON-NLS
2706  } finally {
2707  EamDbUtil.closeStatement(preparedStatement1);
2708  EamDbUtil.closeResultSet(resultSet);
2709  EamDbUtil.closeConnection(conn);
2710  }
2711  }
2712 
2722  @Override
2723  public List<EamGlobalSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2724 
2725  if (correlationType == null) {
2726  throw new EamDbException("Correlation type is null");
2727  }
2728 
2729  List<EamGlobalSet> results = new ArrayList<>();
2730  Connection conn = connect();
2731 
2732  PreparedStatement preparedStatement1 = null;
2733  ResultSet resultSet = null;
2734  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
2735 
2736  try {
2737  preparedStatement1 = conn.prepareStatement(sql1);
2738  resultSet = preparedStatement1.executeQuery();
2739  while (resultSet.next()) {
2740  results.add(getEamGlobalSetFromResultSet(resultSet));
2741  }
2742 
2743  } catch (SQLException ex) {
2744  throw new EamDbException("Error getting reference sets.", ex); // NON-NLS
2745  } finally {
2746  EamDbUtil.closeStatement(preparedStatement1);
2747  EamDbUtil.closeResultSet(resultSet);
2748  EamDbUtil.closeConnection(conn);
2749  }
2750  return results;
2751  }
2752 
2762  @Override
2763  public void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2764  if (eamGlobalFileInstance.getKnownStatus() == null) {
2765  throw new EamDbException("Known status of EamGlobalFileInstance is null");
2766  }
2767  if (correlationType == null) {
2768  throw new EamDbException("Correlation type is null");
2769  }
2770 
2771  Connection conn = connect();
2772 
2773  PreparedStatement preparedStatement = null;
2774 
2775  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2776  + getConflictClause();
2777 
2778  try {
2779  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(correlationType)));
2780  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
2781  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
2782  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
2783  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
2784  preparedStatement.executeUpdate();
2785  } catch (SQLException ex) {
2786  throw new EamDbException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
2787  } finally {
2788  EamDbUtil.closeStatement(preparedStatement);
2789  EamDbUtil.closeConnection(conn);
2790  }
2791  }
2792 
2805  @Override
2806  public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException {
2807  Connection conn = connect();
2808 
2809  PreparedStatement preparedStatement1 = null;
2810  ResultSet resultSet = null;
2811  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
2812 
2813  try {
2814  preparedStatement1 = conn.prepareStatement(sql1);
2815  preparedStatement1.setString(1, referenceSetName);
2816  preparedStatement1.setString(2, version);
2817  resultSet = preparedStatement1.executeQuery();
2818  return (resultSet.next());
2819 
2820  } catch (SQLException ex) {
2821  throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName
2822  + " version: " + version, ex); // NON-NLS
2823  } finally {
2824  EamDbUtil.closeStatement(preparedStatement1);
2825  EamDbUtil.closeResultSet(resultSet);
2826  EamDbUtil.closeConnection(conn);
2827  }
2828  }
2829 
2835  @Override
2836  public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws EamDbException {
2837  if (contentType == null) {
2838  throw new EamDbException("Correlation type is null");
2839  }
2840  if (globalInstances == null) {
2841  throw new EamDbException("Null set of EamGlobalFileInstance");
2842  }
2843 
2844  Connection conn = connect();
2845 
2846  PreparedStatement bulkPs = null;
2847  try {
2848  conn.setAutoCommit(false);
2849 
2850  // FUTURE: have a separate global_files table for each Type.
2851  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2852  + getConflictClause();
2853 
2854  bulkPs = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(contentType)));
2855 
2856  for (EamGlobalFileInstance globalInstance : globalInstances) {
2857  if (globalInstance.getKnownStatus() == null) {
2858  throw new EamDbException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
2859  }
2860 
2861  bulkPs.setInt(1, globalInstance.getGlobalSetID());
2862  bulkPs.setString(2, globalInstance.getMD5Hash());
2863  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
2864  bulkPs.setString(4, globalInstance.getComment());
2865  bulkPs.addBatch();
2866  }
2867 
2868  bulkPs.executeBatch();
2869  conn.commit();
2870  } catch (SQLException | EamDbException ex) {
2871  try {
2872  conn.rollback();
2873  } catch (SQLException ex2) {
2874  // We're alredy in an error state
2875  }
2876  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
2877  } finally {
2878  EamDbUtil.closeStatement(bulkPs);
2879  EamDbUtil.closeConnection(conn);
2880  }
2881  }
2882 
2893  @Override
2894  public List<EamGlobalFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws EamDbException, CorrelationAttributeNormalizationException {
2895  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
2896 
2897  Connection conn = connect();
2898 
2899  List<EamGlobalFileInstance> globalFileInstances = new ArrayList<>();
2900  PreparedStatement preparedStatement1 = null;
2901  ResultSet resultSet = null;
2902  String sql1 = "SELECT * FROM %s WHERE value=?";
2903 
2904  try {
2905  preparedStatement1 = conn.prepareStatement(String.format(sql1, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2906  preparedStatement1.setString(1, normalizeValued);
2907  resultSet = preparedStatement1.executeQuery();
2908  while (resultSet.next()) {
2909  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
2910  }
2911 
2912  } catch (SQLException ex) {
2913  throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS
2914  } finally {
2915  EamDbUtil.closeStatement(preparedStatement1);
2916  EamDbUtil.closeResultSet(resultSet);
2917  EamDbUtil.closeConnection(conn);
2918  }
2919 
2920  return globalFileInstances;
2921  }
2922 
2932  @Override
2933  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws EamDbException {
2934  if (newType == null) {
2935  throw new EamDbException("Correlation type is null");
2936  }
2937  int typeId;
2938  if (-1 == newType.getId()) {
2939  typeId = newCorrelationTypeNotKnownId(newType);
2940  } else {
2941  typeId = newCorrelationTypeKnownId(newType);
2942  }
2943 
2944  return typeId;
2945  }
2946 
2957  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
2958  Connection conn = connect();
2959 
2960  PreparedStatement preparedStatement = null;
2961  PreparedStatement preparedStatementQuery = null;
2962  ResultSet resultSet = null;
2963  int typeId = 0;
2964  String insertSql;
2965  String querySql;
2966  // if we have a known ID, use it, if not (is -1) let the db assign it.
2967  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
2968 
2969  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2970 
2971  try {
2972  preparedStatement = conn.prepareStatement(insertSql);
2973 
2974  preparedStatement.setString(1, newType.getDisplayName());
2975  preparedStatement.setString(2, newType.getDbTableName());
2976  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
2977  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
2978 
2979  preparedStatement.executeUpdate();
2980 
2981  preparedStatementQuery = conn.prepareStatement(querySql);
2982  preparedStatementQuery.setString(1, newType.getDisplayName());
2983  preparedStatementQuery.setString(2, newType.getDbTableName());
2984 
2985  resultSet = preparedStatementQuery.executeQuery();
2986  if (resultSet.next()) {
2987  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2988  typeId = correlationType.getId();
2989  }
2990  } catch (SQLException ex) {
2991  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2992  } finally {
2993  EamDbUtil.closeStatement(preparedStatement);
2994  EamDbUtil.closeStatement(preparedStatementQuery);
2995  EamDbUtil.closeResultSet(resultSet);
2996  EamDbUtil.closeConnection(conn);
2997  }
2998  return typeId;
2999  }
3000 
3010  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
3011  Connection conn = connect();
3012 
3013  PreparedStatement preparedStatement = null;
3014  PreparedStatement preparedStatementQuery = null;
3015  ResultSet resultSet = null;
3016  int typeId = 0;
3017  String insertSql;
3018  String querySql;
3019  // if we have a known ID, use it, if not (is -1) let the db assign it.
3020  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
3021 
3022  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3023 
3024  try {
3025  preparedStatement = conn.prepareStatement(insertSql);
3026 
3027  preparedStatement.setInt(1, newType.getId());
3028  preparedStatement.setString(2, newType.getDisplayName());
3029  preparedStatement.setString(3, newType.getDbTableName());
3030  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
3031  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
3032 
3033  preparedStatement.executeUpdate();
3034 
3035  preparedStatementQuery = conn.prepareStatement(querySql);
3036  preparedStatementQuery.setString(1, newType.getDisplayName());
3037  preparedStatementQuery.setString(2, newType.getDbTableName());
3038 
3039  resultSet = preparedStatementQuery.executeQuery();
3040  if (resultSet.next()) {
3041  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3042  typeId = correlationType.getId();
3043  }
3044  } catch (SQLException ex) {
3045  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
3046  } finally {
3047  EamDbUtil.closeStatement(preparedStatement);
3048  EamDbUtil.closeStatement(preparedStatementQuery);
3049  EamDbUtil.closeResultSet(resultSet);
3050  EamDbUtil.closeConnection(conn);
3051  }
3052  return typeId;
3053  }
3054 
3055  @Override
3056  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws EamDbException {
3057  Connection conn = connect();
3058 
3059  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3060  PreparedStatement preparedStatement = null;
3061  ResultSet resultSet = null;
3062  String sql = "SELECT * FROM correlation_types";
3063 
3064  try {
3065  preparedStatement = conn.prepareStatement(sql);
3066  resultSet = preparedStatement.executeQuery();
3067  while (resultSet.next()) {
3068  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3069  }
3070  return aTypes;
3071 
3072  } catch (SQLException ex) {
3073  throw new EamDbException("Error getting all correlation types.", ex); // NON-NLS
3074  } finally {
3075  EamDbUtil.closeStatement(preparedStatement);
3076  EamDbUtil.closeResultSet(resultSet);
3077  EamDbUtil.closeConnection(conn);
3078  }
3079  }
3080 
3090  @Override
3091  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws EamDbException {
3092  Connection conn = connect();
3093 
3094  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3095  PreparedStatement preparedStatement = null;
3096  ResultSet resultSet = null;
3097  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
3098 
3099  try {
3100  preparedStatement = conn.prepareStatement(sql);
3101  resultSet = preparedStatement.executeQuery();
3102  while (resultSet.next()) {
3103  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3104  }
3105  return aTypes;
3106 
3107  } catch (SQLException ex) {
3108  throw new EamDbException("Error getting enabled correlation types.", ex); // NON-NLS
3109  } finally {
3110  EamDbUtil.closeStatement(preparedStatement);
3111  EamDbUtil.closeResultSet(resultSet);
3112  EamDbUtil.closeConnection(conn);
3113  }
3114  }
3115 
3125  @Override
3126  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws EamDbException {
3127  Connection conn = connect();
3128 
3129  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3130  PreparedStatement preparedStatement = null;
3131  ResultSet resultSet = null;
3132  String sql = "SELECT * FROM correlation_types WHERE supported=1";
3133 
3134  try {
3135  preparedStatement = conn.prepareStatement(sql);
3136  resultSet = preparedStatement.executeQuery();
3137  while (resultSet.next()) {
3138  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3139  }
3140  return aTypes;
3141 
3142  } catch (SQLException ex) {
3143  throw new EamDbException("Error getting supported correlation types.", ex); // NON-NLS
3144  } finally {
3145  EamDbUtil.closeStatement(preparedStatement);
3146  EamDbUtil.closeResultSet(resultSet);
3147  EamDbUtil.closeConnection(conn);
3148  }
3149  }
3150 
3158  @Override
3159  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws EamDbException {
3160  Connection conn = connect();
3161 
3162  PreparedStatement preparedStatement = null;
3163  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3164 
3165  try {
3166  preparedStatement = conn.prepareStatement(sql);
3167  preparedStatement.setString(1, aType.getDisplayName());
3168  preparedStatement.setString(2, aType.getDbTableName());
3169  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3170  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3171  preparedStatement.setInt(5, aType.getId());
3172  preparedStatement.executeUpdate();
3173  typeCache.put(aType.getId(), aType);
3174  } catch (SQLException ex) {
3175  throw new EamDbException("Error updating correlation type.", ex); // NON-NLS
3176  } finally {
3177  EamDbUtil.closeStatement(preparedStatement);
3178  EamDbUtil.closeConnection(conn);
3179  }
3180 
3181  }
3182 
3192  @Override
3193  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws EamDbException {
3194  try {
3195  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3196  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3197  //lambda valueloader returned a null value and cache can not store null values this is normal if the correlation type does not exist in the central repo yet
3198  return null;
3199  } catch (ExecutionException ex) {
3200  throw new EamDbException("Error getting correlation type", ex);
3201  }
3202  }
3203 
3213  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws EamDbException {
3214  Connection conn = connect();
3215 
3217  PreparedStatement preparedStatement = null;
3218  ResultSet resultSet = null;
3219  String sql = "SELECT * FROM correlation_types WHERE id=?";
3220 
3221  try {
3222  preparedStatement = conn.prepareStatement(sql);
3223  preparedStatement.setInt(1, typeId);
3224  resultSet = preparedStatement.executeQuery();
3225  if (resultSet.next()) {
3226  aType = getCorrelationTypeFromResultSet(resultSet);
3227  return aType;
3228  } else {
3229  throw new EamDbException("Failed to find entry for correlation type ID = " + typeId);
3230  }
3231 
3232  } catch (SQLException ex) {
3233  throw new EamDbException("Error getting correlation type by id.", ex); // NON-NLS
3234  } finally {
3235  EamDbUtil.closeStatement(preparedStatement);
3236  EamDbUtil.closeResultSet(resultSet);
3237  EamDbUtil.closeConnection(conn);
3238  }
3239  }
3240 
3251  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3252  if (null == resultSet) {
3253  return null;
3254  }
3255 
3256  EamOrganization eamOrg = null;
3257 
3258  resultSet.getInt("org_id");
3259  if (!resultSet.wasNull()) {
3260 
3261  eamOrg = new EamOrganization(resultSet.getInt("org_id"),
3262  resultSet.getString("org_name"),
3263  resultSet.getString("poc_name"),
3264  resultSet.getString("poc_email"),
3265  resultSet.getString("poc_phone"));
3266  }
3267 
3268  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3269  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3270  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3271 
3272  return eamCase;
3273  }
3274 
3275  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3276  if (null == resultSet) {
3277  return null;
3278  }
3279 
3280  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3281  resultSet.getInt("case_id"),
3282  resultSet.getInt("id"),
3283  resultSet.getString("device_id"),
3284  resultSet.getString("name"),
3285  resultSet.getLong("datasource_obj_id"),
3286  resultSet.getString("md5"),
3287  resultSet.getString("sha1"),
3288  resultSet.getString("sha256")
3289  );
3290 
3291  return eamDataSource;
3292  }
3293 
3294  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws EamDbException, SQLException {
3295  if (null == resultSet) {
3296  return null;
3297  }
3298 
3300  resultSet.getInt("id"),
3301  resultSet.getString("display_name"),
3302  resultSet.getString("db_table_name"),
3303  resultSet.getBoolean("supported"),
3304  resultSet.getBoolean("enabled")
3305  );
3306 
3307  return eamArtifactType;
3308  }
3309 
3320  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3321  if (null == resultSet) {
3322  return null;
3323  }
3324  return new CorrelationAttributeInstance(
3325  aType,
3326  resultSet.getString("value"),
3327  resultSet.getInt("id"),
3328  new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
3330  resultSet.getInt("case_id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3331  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3332  resultSet.getString("file_path"),
3333  resultSet.getString("comment"),
3334  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3335  resultSet.getLong("file_obj_id"));
3336  }
3337 
3338  private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3339  if (null == resultSet) {
3340  return null;
3341  }
3342 
3343  return new EamOrganization(
3344  resultSet.getInt("id"),
3345  resultSet.getString("org_name"),
3346  resultSet.getString("poc_name"),
3347  resultSet.getString("poc_email"),
3348  resultSet.getString("poc_phone")
3349  );
3350  }
3351 
3352  private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
3353  if (null == resultSet) {
3354  return null;
3355  }
3356 
3357  return new EamGlobalSet(
3358  resultSet.getInt("id"),
3359  resultSet.getInt("org_id"),
3360  resultSet.getString("set_name"),
3361  resultSet.getString("version"),
3362  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3363  resultSet.getBoolean("read_only"),
3364  EamDb.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3365  LocalDate.parse(resultSet.getString("import_date"))
3366  );
3367  }
3368 
3369  private EamGlobalFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3370  if (null == resultSet) {
3371  return null;
3372  }
3373 
3374  return new EamGlobalFileInstance(
3375  resultSet.getInt("id"),
3376  resultSet.getInt("reference_set_id"),
3377  resultSet.getString("value"),
3378  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3379  resultSet.getString("comment")
3380  );
3381  }
3382 
3393  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3394 
3400  @Messages({"AbstractSqlEamDb.upgradeSchema.incompatible=The selected Central Repository is not compatible with the current version of the application, please upgrade the application if you wish to use this Central Repository."})
3401  @Override
3402  public void upgradeSchema() throws EamDbException, SQLException, IncompatibleCentralRepoException {
3403 
3404  ResultSet resultSet = null;
3405  Statement statement = null;
3406  PreparedStatement preparedStatement = null;
3407  Connection conn = null;
3408  EamDbPlatformEnum selectedPlatform = null;
3409  try {
3410 
3411  conn = connect(false);
3412  conn.setAutoCommit(false);
3413  statement = conn.createStatement();
3414  selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
3415  int minorVersion = 0;
3416  String minorVersionStr = null;
3417  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "'");
3418  if (resultSet.next()) {
3419  minorVersionStr = resultSet.getString("value");
3420  try {
3421  minorVersion = Integer.parseInt(minorVersionStr);
3422  } catch (NumberFormatException ex) {
3423  throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", ex);
3424  }
3425  } else {
3426  throw new EamDbException("Failed to read schema minor version from db_info table");
3427  }
3428 
3429  int majorVersion = 0;
3430  String majorVersionStr = null;
3431  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "'");
3432  if (resultSet.next()) {
3433  majorVersionStr = resultSet.getString("value");
3434  try {
3435  majorVersion = Integer.parseInt(majorVersionStr);
3436  } catch (NumberFormatException ex) {
3437  throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", ex);
3438  }
3439  } else {
3440  throw new EamDbException("Failed to read schema major version from db_info table");
3441  }
3442 
3443  /*
3444  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3445  * 4.10.0. The consequence of the bug is that the schema version
3446  * number is always reset to 1.0 or 1.1 if a Central Repository is
3447  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3448  * there is an effort in updates to 1.2 and greater to not retry
3449  * schema updates that may already have been done once.
3450  */
3451  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3452 
3453  //compare the major versions for compatability
3454  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3455  //because it is specific to case db schema versions only supporting major versions greater than 1
3456  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3457  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3458  }
3459  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3460  logger.log(Level.INFO, "Central Repository is up to date");
3461  return;
3462  }
3463  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3464  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3465  return;
3466  }
3467 
3468  /*
3469  * Update to 1.1
3470  */
3471  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3472  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3473  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3474  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3475 
3476  // There's an outide chance that the user has already made an organization with the default name,
3477  // and the default org being missing will not impact any database operations, so continue on
3478  // regardless of whether this succeeds.
3479  EamDbUtil.insertDefaultOrganization(conn);
3480  }
3481 
3482  /*
3483  * Update to 1.2
3484  */
3485  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3486  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3487  final String addSsidTableTemplate;
3488  final String addCaseIdIndexTemplate;
3489  final String addDataSourceIdIndexTemplate;
3490  final String addValueIndexTemplate;
3491  final String addKnownStatusIndexTemplate;
3492  final String addObjectIdIndexTemplate;
3493 
3494  final String addAttributeSql;
3495  //get the data base specific code for creating a new _instance table
3496  switch (selectedPlatform) {
3497  case POSTGRESQL:
3498  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3499 
3500  addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
3501  addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
3502  addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
3503  addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
3504  addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
3505  addObjectIdIndexTemplate = PostgresEamDbSettings.getAddObjectIdIndexTemplate();
3506  break;
3507  case SQLITE:
3508  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3509 
3510  addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
3511  addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
3512  addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
3513  addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
3514  addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
3515  addObjectIdIndexTemplate = SqliteEamDbSettings.getAddObjectIdIndexTemplate();
3516  break;
3517  default:
3518  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
3519  }
3520  final String dataSourcesTableName = "data_sources";
3521  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3522  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3523  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3524  }
3525  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3526  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3527  List<String> instaceTablesToAdd = new ArrayList<>();
3528  //update central repository to be able to store new correlation attributes
3529  final String wirelessNetworksDbTableName = "wireless_networks";
3530  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3531  final String macAddressDbTableName = "mac_address";
3532  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3533  final String imeiNumberDbTableName = "imei_number";
3534  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3535  final String iccidNumberDbTableName = "iccid_number";
3536  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3537  final String imsiNumberDbTableName = "imsi_number";
3538  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3539 
3540  //add the wireless_networks attribute to the correlation_types table
3541  preparedStatement = conn.prepareStatement(addAttributeSql);
3542  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3543  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3544  preparedStatement.setString(3, wirelessNetworksDbTableName);
3545  preparedStatement.setInt(4, 1);
3546  preparedStatement.setInt(5, 1);
3547  preparedStatement.execute();
3548 
3549  //add the mac_address attribute to the correlation_types table
3550  preparedStatement = conn.prepareStatement(addAttributeSql);
3551  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3552  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3553  preparedStatement.setString(3, macAddressDbTableName);
3554  preparedStatement.setInt(4, 1);
3555  preparedStatement.setInt(5, 1);
3556  preparedStatement.execute();
3557 
3558  //add the imei_number attribute to the correlation_types table
3559  preparedStatement = conn.prepareStatement(addAttributeSql);
3560  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3561  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3562  preparedStatement.setString(3, imeiNumberDbTableName);
3563  preparedStatement.setInt(4, 1);
3564  preparedStatement.setInt(5, 1);
3565  preparedStatement.execute();
3566 
3567  //add the imsi_number attribute to the correlation_types table
3568  preparedStatement = conn.prepareStatement(addAttributeSql);
3569  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3570  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3571  preparedStatement.setString(3, imsiNumberDbTableName);
3572  preparedStatement.setInt(4, 1);
3573  preparedStatement.setInt(5, 1);
3574  preparedStatement.execute();
3575 
3576  //add the iccid_number attribute to the correlation_types table
3577  preparedStatement = conn.prepareStatement(addAttributeSql);
3578  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3579  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3580  preparedStatement.setString(3, iccidNumberDbTableName);
3581  preparedStatement.setInt(4, 1);
3582  preparedStatement.setInt(5, 1);
3583  preparedStatement.execute();
3584 
3585  //create a new _instances tables and add indexes for their columns
3586  for (String tableName : instaceTablesToAdd) {
3587  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3588  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3589  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3590  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3591  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3592  }
3593 
3594  //add file_obj_id column to _instances table which do not already have it
3595  String instance_type_dbname;
3596  final String objectIdColumnName = "file_obj_id";
3598  instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
3599  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3600  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3601  }
3602  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3603  }
3604 
3605  /*
3606  * Add hash columns to the data_sources table.
3607  */
3608  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3609  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3610  }
3611  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3612  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3613  }
3614  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3615  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3616  }
3617 
3618  /*
3619  * Drop the db_info table and add it back in with the name
3620  * column having a UNIQUE constraint. The name column could now
3621  * be used as the primary key, but the essentially useless id
3622  * column is retained for the sake of backwards compatibility.
3623  * Note that the creation schema version number is set to 0.0 to
3624  * indicate that it is unknown.
3625  */
3626  String creationMajorVer;
3627  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3628  if (resultSet.next()) {
3629  creationMajorVer = resultSet.getString("value");
3630  } else {
3631  creationMajorVer = "0";
3632  }
3633  String creationMinorVer;
3634  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3635  if (resultSet.next()) {
3636  creationMinorVer = resultSet.getString("value");
3637  } else {
3638  creationMinorVer = "0";
3639  }
3640  statement.execute("DROP TABLE db_info");
3641  if (selectedPlatform == EamDbPlatformEnum.POSTGRESQL) {
3642  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3643  } else {
3644  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3645  }
3646  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3647  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3648  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3649  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3650  }
3651  /*
3652  * Update to 1.3
3653  */
3654  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3655  switch (selectedPlatform) {
3656  case POSTGRESQL:
3657  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3658  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3659  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
3660 
3661  break;
3662  case SQLITE:
3663  statement.execute("DROP INDEX IF EXISTS data_sources_name");
3664  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
3665  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
3666  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3667  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
3668  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
3669  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
3670  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
3671  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
3672  statement.execute(SqliteEamDbSettings.getAddDataSourcesNameIndexStatement());
3673  statement.execute(SqliteEamDbSettings.getAddDataSourcesObjectIdIndexStatement());
3674  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
3675  statement.execute("DROP TABLE old_data_sources");
3676  break;
3677  default:
3678  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
3679  }
3680  }
3681  updateSchemaVersion(conn);
3682  conn.commit();
3683  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
3684 
3685  } catch (SQLException | EamDbException ex) {
3686  try {
3687  if (conn != null) {
3688  conn.rollback();
3689  }
3690  } catch (SQLException ex2) {
3691  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
3692  }
3693  throw ex;
3694  } finally {
3695  EamDbUtil.closeResultSet(resultSet);
3696  EamDbUtil.closeStatement(preparedStatement);
3697  EamDbUtil.closeStatement(statement);
3698  EamDbUtil.closeConnection(conn);
3699  }
3700  }
3701 
3702 }
static String correlationTypeToInstanceTableName(CorrelationAttributeInstance.Type type)
Definition: EamDbUtil.java:330
static TimingMetric getTimingMetric(String name)
static String normalize(CorrelationAttributeInstance.Type attributeType, String data)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
static void submitTimingMetric(TimingMetric metric)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static String correlationTypeToReferenceTableName(CorrelationAttributeInstance.Type type)
Definition: EamDbUtil.java:341

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.