Autopsy  4.13.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 as instance_id,"
1121  + tableName
1122  + ".value,"
1123  + tableName
1124  + ".file_obj_id,"
1125  + " cases.*, organizations.org_name, organizations.poc_name, organizations.poc_email, organizations.poc_phone, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, 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 organizations ON cases.org_id=organizations.id"
1131  + " LEFT JOIN data_sources ON "
1132  + tableName
1133  + ".data_source_id=data_sources.id"
1134  + " WHERE value IN (";
1135  StringBuilder inValuesBuilder = new StringBuilder(sql);
1136  for (String value : values) {
1137  if (value != null) {
1138  inValuesBuilder.append("'");
1139  inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1140  inValuesBuilder.append("',");
1141  }
1142  }
1143  inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1144  inValuesBuilder.append(")");
1145  return inValuesBuilder.toString();
1146  }
1147 
1162  private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, EamDbException {
1163  Connection conn = connect();
1164  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1165  CorrelationAttributeInstance artifactInstance;
1166  PreparedStatement preparedStatement = null;
1167  ResultSet resultSet = null;
1168  try {
1169  preparedStatement = conn.prepareStatement(sql);
1170  resultSet = preparedStatement.executeQuery();
1171  while (resultSet.next()) {
1172  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1173  artifactInstances.add(artifactInstance);
1174  }
1175  } catch (SQLException ex) {
1176  throw new EamDbException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1177  } finally {
1178  EamDbUtil.closeStatement(preparedStatement);
1179  EamDbUtil.closeResultSet(resultSet);
1180  EamDbUtil.closeConnection(conn);
1181  }
1182  return artifactInstances;
1183  }
1184 
1195  @Override
1196  public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1197  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1198 
1199  Connection conn = connect();
1200 
1201  Long instanceCount = 0L;
1202  PreparedStatement preparedStatement = null;
1203  ResultSet resultSet = null;
1204 
1205  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1206  String sql
1207  = "SELECT count(*) FROM "
1208  + tableName
1209  + " WHERE value=?";
1210 
1211  try {
1212  preparedStatement = conn.prepareStatement(sql);
1213  preparedStatement.setString(1, normalizedValue);
1214  resultSet = preparedStatement.executeQuery();
1215  resultSet.next();
1216  instanceCount = resultSet.getLong(1);
1217  } catch (SQLException ex) {
1218  throw new EamDbException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1219  } finally {
1220  EamDbUtil.closeStatement(preparedStatement);
1221  EamDbUtil.closeResultSet(resultSet);
1222  EamDbUtil.closeConnection(conn);
1223  }
1224 
1225  return instanceCount;
1226  }
1227 
1228  @Override
1229  public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws EamDbException, CorrelationAttributeNormalizationException {
1230  if (corAttr == null) {
1231  throw new EamDbException("CorrelationAttribute is null");
1232  }
1233  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1234  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1235  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1236  return commonalityPercentage.intValue();
1237  }
1238 
1249  @Override
1250  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1251  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1252 
1253  Connection conn = connect();
1254 
1255  Long instanceCount = 0L;
1256  PreparedStatement preparedStatement = null;
1257  ResultSet resultSet = null;
1258 
1259  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1260  String sql
1261  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1262  + tableName
1263  + " WHERE value=?) AS "
1264  + tableName
1265  + "_distinct_case_data_source_tuple";
1266 
1267  try {
1268  preparedStatement = conn.prepareStatement(sql);
1269  preparedStatement.setString(1, normalizedValue);
1270  resultSet = preparedStatement.executeQuery();
1271  resultSet.next();
1272  instanceCount = resultSet.getLong(1);
1273  } catch (SQLException ex) {
1274  throw new EamDbException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1275  } finally {
1276  EamDbUtil.closeStatement(preparedStatement);
1277  EamDbUtil.closeResultSet(resultSet);
1278  EamDbUtil.closeConnection(conn);
1279  }
1280 
1281  return instanceCount;
1282  }
1283 
1284  @Override
1285  public Long getCountUniqueDataSources() throws EamDbException {
1286  Connection conn = connect();
1287 
1288  Long instanceCount = 0L;
1289  PreparedStatement preparedStatement = null;
1290  ResultSet resultSet = null;
1291 
1292  String stmt = "SELECT count(*) FROM data_sources";
1293 
1294  try {
1295  preparedStatement = conn.prepareStatement(stmt);
1296  resultSet = preparedStatement.executeQuery();
1297  resultSet.next();
1298  instanceCount = resultSet.getLong(1);
1299  } catch (SQLException ex) {
1300  throw new EamDbException("Error counting data sources.", ex); // NON-NLS
1301  } finally {
1302  EamDbUtil.closeStatement(preparedStatement);
1303  EamDbUtil.closeResultSet(resultSet);
1304  EamDbUtil.closeConnection(conn);
1305  }
1306 
1307  return instanceCount;
1308  }
1309 
1321  @Override
1322  public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws EamDbException {
1323  Connection conn = connect();
1324 
1325  Long instanceCount = 0L;
1326  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1327  PreparedStatement preparedStatement = null;
1328  ResultSet resultSet = null;
1329 
1330  //Create query to get count of all instances in the database for the specified case specific data source
1331  String sql = "SELECT 0 ";
1332 
1333  for (CorrelationAttributeInstance.Type type : artifactTypes) {
1334  String table_name = EamDbUtil.correlationTypeToInstanceTableName(type);
1335  sql
1336  += "+ (SELECT count(*) FROM "
1337  + table_name
1338  + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1339  }
1340  try {
1341  preparedStatement = conn.prepareStatement(sql);
1342 
1343  resultSet = preparedStatement.executeQuery();
1344  resultSet.next();
1345  instanceCount = resultSet.getLong(1);
1346  } catch (SQLException ex) {
1347  throw new EamDbException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1348  } finally {
1349  EamDbUtil.closeStatement(preparedStatement);
1350  EamDbUtil.closeResultSet(resultSet);
1351  EamDbUtil.closeConnection(conn);
1352  }
1353 
1354  return instanceCount;
1355  }
1356 
1364  @Override
1365  public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws EamDbException {
1366 
1367  if (eamArtifact.getCorrelationType() == null) {
1368  throw new EamDbException("Correlation type is null");
1369  }
1370 
1371  synchronized (bulkArtifacts) {
1372  bulkArtifacts.get(EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1373  bulkArtifactsCount++;
1374 
1375  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1376  commitAttributeInstancesBulk();
1377  }
1378  }
1379  }
1380 
1386  protected abstract String getConflictClause();
1387 
1392  @Override
1393  public void commitAttributeInstancesBulk() throws EamDbException {
1394  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1395 
1396  Connection conn = connect();
1397  PreparedStatement bulkPs = null;
1398 
1399  try {
1400  synchronized (bulkArtifacts) {
1401  if (bulkArtifactsCount == 0) {
1402  return;
1403  }
1404 
1405  for (String tableName : bulkArtifacts.keySet()) {
1406 
1407  String sql
1408  = "INSERT INTO "
1409  + tableName
1410  + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1411  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1412  + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1413  + getConflictClause();
1414 
1415  bulkPs = conn.prepareStatement(sql);
1416 
1417  Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1418  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1419 
1420  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1421 
1422  if (eamArtifact.getCorrelationCase() == null) {
1423  throw new EamDbException("CorrelationAttributeInstance case is null for: "
1424  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1425  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1426  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1427  }
1428  if (eamArtifact.getCorrelationDataSource() == null) {
1429  throw new EamDbException("CorrelationAttributeInstance data source is null for: "
1430  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1431  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1432  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1433  }
1434  if (eamArtifact.getKnownStatus() == null) {
1435  throw new EamDbException("CorrelationAttributeInstance known status is null for: "
1436  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1437  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1438  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1439  + "\n\tEam Instance: "
1440  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1441  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1442  }
1443 
1444  if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1445  bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1446  bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1447  bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1448  bulkPs.setString(4, eamArtifact.getCorrelationValue());
1449  bulkPs.setString(5, eamArtifact.getFilePath());
1450  bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1451  if ("".equals(eamArtifact.getComment())) {
1452  bulkPs.setNull(7, Types.INTEGER);
1453  } else {
1454  bulkPs.setString(7, eamArtifact.getComment());
1455  }
1456  bulkPs.setLong(8, eamArtifact.getFileObjectId());
1457  bulkPs.addBatch();
1458  } else {
1459  logger.log(Level.WARNING, ("Artifact value too long for central repository."
1460  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1461  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1462  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1463  + "\n\tEam Instance: "
1464  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1465  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1466  + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1467  }
1468  }
1469 
1470  }
1471 
1472  bulkPs.executeBatch();
1473  bulkArtifacts.get(tableName).clear();
1474  }
1475 
1476  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Correlation Engine: Bulk insert");
1477  HealthMonitor.submitTimingMetric(timingMetric);
1478 
1479  // Reset state
1480  bulkArtifactsCount = 0;
1481  }
1482  } catch (SQLException ex) {
1483  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
1484  } finally {
1485  EamDbUtil.closeStatement(bulkPs);
1486  EamDbUtil.closeConnection(conn);
1487  }
1488  }
1489 
1493  @Override
1494  public void bulkInsertCases(List<CorrelationCase> cases) throws EamDbException {
1495  if (cases == null) {
1496  throw new EamDbException("cases argument is null");
1497  }
1498 
1499  if (cases.isEmpty()) {
1500  return;
1501  }
1502 
1503  Connection conn = connect();
1504 
1505  int counter = 0;
1506  PreparedStatement bulkPs = null;
1507  try {
1508  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1509  + "examiner_name, examiner_email, examiner_phone, notes) "
1510  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1511  + getConflictClause();
1512  bulkPs = conn.prepareStatement(sql);
1513 
1514  for (CorrelationCase eamCase : cases) {
1515  bulkPs.setString(1, eamCase.getCaseUUID());
1516  if (null == eamCase.getOrg()) {
1517  bulkPs.setNull(2, Types.INTEGER);
1518  } else {
1519  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1520  }
1521  bulkPs.setString(3, eamCase.getDisplayName());
1522  bulkPs.setString(4, eamCase.getCreationDate());
1523 
1524  if ("".equals(eamCase.getCaseNumber())) {
1525  bulkPs.setNull(5, Types.INTEGER);
1526  } else {
1527  bulkPs.setString(5, eamCase.getCaseNumber());
1528  }
1529  if ("".equals(eamCase.getExaminerName())) {
1530  bulkPs.setNull(6, Types.INTEGER);
1531  } else {
1532  bulkPs.setString(6, eamCase.getExaminerName());
1533  }
1534  if ("".equals(eamCase.getExaminerEmail())) {
1535  bulkPs.setNull(7, Types.INTEGER);
1536  } else {
1537  bulkPs.setString(7, eamCase.getExaminerEmail());
1538  }
1539  if ("".equals(eamCase.getExaminerPhone())) {
1540  bulkPs.setNull(8, Types.INTEGER);
1541  } else {
1542  bulkPs.setString(8, eamCase.getExaminerPhone());
1543  }
1544  if ("".equals(eamCase.getNotes())) {
1545  bulkPs.setNull(9, Types.INTEGER);
1546  } else {
1547  bulkPs.setString(9, eamCase.getNotes());
1548  }
1549 
1550  bulkPs.addBatch();
1551 
1552  counter++;
1553 
1554  // limit a batch's max size to bulkArtifactsThreshold
1555  if (counter >= bulkArtifactsThreshold) {
1556  bulkPs.executeBatch();
1557  counter = 0;
1558  }
1559  }
1560  // send the remaining batch records
1561  bulkPs.executeBatch();
1562  } catch (SQLException ex) {
1563  throw new EamDbException("Error inserting bulk cases.", ex); // NON-NLS
1564  } finally {
1565  EamDbUtil.closeStatement(bulkPs);
1566  EamDbUtil.closeConnection(conn);
1567  }
1568  }
1569 
1579  @Override
1580  public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws EamDbException {
1581 
1582  if (eamArtifact == null) {
1583  throw new EamDbException("CorrelationAttributeInstance is null");
1584  }
1585  if (eamArtifact.getCorrelationCase() == null) {
1586  throw new EamDbException("Correlation case is null");
1587  }
1588  if (eamArtifact.getCorrelationDataSource() == null) {
1589  throw new EamDbException("Correlation data source is null");
1590  }
1591  Connection conn = connect();
1592  PreparedStatement preparedQuery = null;
1593  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1594  String sqlUpdate
1595  = "UPDATE "
1596  + tableName
1597  + " SET comment=? "
1598  + "WHERE case_id=? "
1599  + "AND data_source_id=? "
1600  + "AND value=? "
1601  + "AND file_path=?";
1602 
1603  try {
1604  preparedQuery = conn.prepareStatement(sqlUpdate);
1605  preparedQuery.setString(1, eamArtifact.getComment());
1606  preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1607  preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1608  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1609  preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1610  preparedQuery.executeUpdate();
1611  } catch (SQLException ex) {
1612  throw new EamDbException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1613  } finally {
1614  EamDbUtil.closeStatement(preparedQuery);
1615  EamDbUtil.closeConnection(conn);
1616  }
1617  }
1618 
1633  @Override
1634  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1635  CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException {
1636 
1637  if (correlationCase == null) {
1638  throw new EamDbException("Correlation case is null");
1639  }
1640 
1641  Connection conn = connect();
1642 
1643  PreparedStatement preparedStatement = null;
1644  ResultSet resultSet = null;
1645  CorrelationAttributeInstance correlationAttributeInstance = null;
1646 
1647  try {
1648 
1649  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1650  String sql
1651  = "SELECT id, value, file_path, known_status, comment FROM "
1652  + tableName
1653  + " WHERE case_id=?"
1654  + " AND file_obj_id=?";
1655 
1656  preparedStatement = conn.prepareStatement(sql);
1657  preparedStatement.setInt(1, correlationCase.getID());
1658  preparedStatement.setInt(2, (int) objectID);
1659  resultSet = preparedStatement.executeQuery();
1660  if (resultSet.next()) {
1661  int instanceId = resultSet.getInt(1);
1662  String value = resultSet.getString(2);
1663  String filePath = resultSet.getString(3);
1664  int knownStatus = resultSet.getInt(4);
1665  String comment = resultSet.getString(5);
1666 
1667  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1668  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1669  }
1670  } catch (SQLException ex) {
1671  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1672  } finally {
1673  EamDbUtil.closeStatement(preparedStatement);
1674  EamDbUtil.closeResultSet(resultSet);
1675  EamDbUtil.closeConnection(conn);
1676  }
1677 
1678  return correlationAttributeInstance;
1679  }
1680 
1695  @Override
1696  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1697  CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException, CorrelationAttributeNormalizationException {
1698 
1699  if (correlationCase == null) {
1700  throw new EamDbException("Correlation case is null");
1701  }
1702  if (correlationDataSource == null) {
1703  throw new EamDbException("Correlation data source is null");
1704  }
1705  if (filePath == null) {
1706  throw new EamDbException("Correlation file path 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  String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1717 
1718  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
1719  String sql
1720  = "SELECT id, known_status, comment FROM "
1721  + tableName
1722  + " WHERE case_id=?"
1723  + " AND data_source_id=?"
1724  + " AND value=?"
1725  + " AND file_path=?";
1726 
1727  preparedStatement = conn.prepareStatement(sql);
1728  preparedStatement.setInt(1, correlationCase.getID());
1729  preparedStatement.setInt(2, correlationDataSource.getID());
1730  preparedStatement.setString(3, normalizedValue);
1731  preparedStatement.setString(4, filePath.toLowerCase());
1732  resultSet = preparedStatement.executeQuery();
1733  if (resultSet.next()) {
1734  int instanceId = resultSet.getInt(1);
1735  int knownStatus = resultSet.getInt(2);
1736  String comment = resultSet.getString(3);
1737  //null objectId used because we only fall back to using this method when objectID was not available
1738  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1739  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
1740  }
1741  } catch (SQLException ex) {
1742  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1743  } finally {
1744  EamDbUtil.closeStatement(preparedStatement);
1745  EamDbUtil.closeResultSet(resultSet);
1746  EamDbUtil.closeConnection(conn);
1747  }
1748 
1749  return correlationAttributeInstance;
1750  }
1751 
1762  @Override
1763  public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
1764  if (eamArtifact == null) {
1765  throw new EamDbException("CorrelationAttribute is null");
1766  }
1767  if (knownStatus == null) {
1768  throw new EamDbException("Known status is null");
1769  }
1770 
1771  if (eamArtifact.getCorrelationCase() == null) {
1772  throw new EamDbException("Correlation case is null");
1773  }
1774  if (eamArtifact.getCorrelationDataSource() == null) {
1775  throw new EamDbException("Correlation data source is null");
1776  }
1777 
1778  Connection conn = connect();
1779 
1780  PreparedStatement preparedUpdate = null;
1781  PreparedStatement preparedQuery = null;
1782  ResultSet resultSet = null;
1783 
1784  String tableName = EamDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1785 
1786  String sqlQuery
1787  = "SELECT id FROM "
1788  + tableName
1789  + " WHERE case_id=? "
1790  + "AND data_source_id=? "
1791  + "AND value=? "
1792  + "AND file_path=?";
1793 
1794  String sqlUpdate
1795  = "UPDATE "
1796  + tableName
1797  + " SET known_status=?, comment=? "
1798  + "WHERE id=?";
1799 
1800  try {
1801  preparedQuery = conn.prepareStatement(sqlQuery);
1802  preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
1803  preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1804  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
1805  preparedQuery.setString(4, eamArtifact.getFilePath());
1806  resultSet = preparedQuery.executeQuery();
1807  if (resultSet.next()) {
1808  int instance_id = resultSet.getInt("id");
1809  preparedUpdate = conn.prepareStatement(sqlUpdate);
1810 
1811  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
1812  // NOTE: if the user tags the same instance as BAD multiple times,
1813  // the comment from the most recent tagging is the one that will
1814  // prevail in the DB.
1815  if ("".equals(eamArtifact.getComment())) {
1816  preparedUpdate.setNull(2, Types.INTEGER);
1817  } else {
1818  preparedUpdate.setString(2, eamArtifact.getComment());
1819  }
1820  preparedUpdate.setInt(3, instance_id);
1821 
1822  preparedUpdate.executeUpdate();
1823  } else {
1824  // In this case, the user is tagging something that isn't in the database,
1825  // which means the case and/or datasource may also not be in the database.
1826  // We could improve effiency by keeping a list of all datasources and cases
1827  // in the database, but we don't expect the user to be tagging large numbers
1828  // of items (that didn't have the CE ingest module run on them) at once.
1829  CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
1830  if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
1831  newDataSource(eamArtifact.getCorrelationDataSource());
1832  }
1833  eamArtifact.setKnownStatus(knownStatus);
1834  addArtifactInstance(eamArtifact);
1835  }
1836 
1837  } catch (SQLException ex) {
1838  throw new EamDbException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
1839  } finally {
1840  EamDbUtil.closeStatement(preparedUpdate);
1841  EamDbUtil.closeStatement(preparedQuery);
1842  EamDbUtil.closeResultSet(resultSet);
1843  EamDbUtil.closeConnection(conn);
1844  }
1845  }
1846 
1855  @Override
1856  public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1857 
1858  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1859 
1860  Connection conn = connect();
1861 
1862  Long badInstances = 0L;
1863  PreparedStatement preparedStatement = null;
1864  ResultSet resultSet = null;
1865 
1866  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1867  String sql
1868  = "SELECT count(*) FROM "
1869  + tableName
1870  + " WHERE value=? AND known_status=?";
1871 
1872  try {
1873  preparedStatement = conn.prepareStatement(sql);
1874  preparedStatement.setString(1, normalizedValue);
1875  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1876  resultSet = preparedStatement.executeQuery();
1877  resultSet.next();
1878  badInstances = resultSet.getLong(1);
1879  } catch (SQLException ex) {
1880  throw new EamDbException("Error getting count of notable artifact instances.", ex); // NON-NLS
1881  } finally {
1882  EamDbUtil.closeStatement(preparedStatement);
1883  EamDbUtil.closeResultSet(resultSet);
1884  EamDbUtil.closeConnection(conn);
1885  }
1886 
1887  return badInstances;
1888  }
1889 
1902  @Override
1903  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1904 
1905  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1906 
1907  Connection conn = connect();
1908 
1909  Collection<String> caseNames = new LinkedHashSet<>();
1910 
1911  PreparedStatement preparedStatement = null;
1912  ResultSet resultSet = null;
1913 
1914  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1915  String sql
1916  = "SELECT DISTINCT case_name FROM "
1917  + tableName
1918  + " INNER JOIN cases ON "
1919  + tableName
1920  + ".case_id=cases.id WHERE "
1921  + tableName
1922  + ".value=? AND "
1923  + tableName
1924  + ".known_status=?";
1925 
1926  try {
1927  preparedStatement = conn.prepareStatement(sql);
1928  preparedStatement.setString(1, normalizedValue);
1929  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
1930  resultSet = preparedStatement.executeQuery();
1931  while (resultSet.next()) {
1932  caseNames.add(resultSet.getString("case_name"));
1933  }
1934  } catch (SQLException ex) {
1935  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1936  } finally {
1937  EamDbUtil.closeStatement(preparedStatement);
1938  EamDbUtil.closeResultSet(resultSet);
1939  EamDbUtil.closeConnection(conn);
1940  }
1941 
1942  return caseNames.stream().collect(Collectors.toList());
1943  }
1944 
1957  @Override
1958  public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
1959 
1960  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1961 
1962  Connection conn = connect();
1963 
1964  Collection<String> caseNames = new LinkedHashSet<>();
1965 
1966  PreparedStatement preparedStatement = null;
1967  ResultSet resultSet = null;
1968 
1969  String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
1970  String sql
1971  = "SELECT DISTINCT case_name FROM "
1972  + tableName
1973  + " INNER JOIN cases ON "
1974  + tableName
1975  + ".case_id=cases.id WHERE "
1976  + tableName
1977  + ".value=? ";
1978 
1979  try {
1980  preparedStatement = conn.prepareStatement(sql);
1981  preparedStatement.setString(1, normalizedValue);
1982  resultSet = preparedStatement.executeQuery();
1983  while (resultSet.next()) {
1984  caseNames.add(resultSet.getString("case_name"));
1985  }
1986  } catch (SQLException ex) {
1987  throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
1988  } finally {
1989  EamDbUtil.closeStatement(preparedStatement);
1990  EamDbUtil.closeResultSet(resultSet);
1991  EamDbUtil.closeConnection(conn);
1992  }
1993 
1994  return caseNames.stream().collect(Collectors.toList());
1995  }
1996 
2004  @Override
2005  public void deleteReferenceSet(int referenceSetID) throws EamDbException {
2006  deleteReferenceSetEntries(referenceSetID);
2007  deleteReferenceSetEntry(referenceSetID);
2008  }
2009 
2017  private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException {
2018  Connection conn = connect();
2019 
2020  PreparedStatement preparedStatement = null;
2021  String sql = "DELETE FROM reference_sets WHERE id=?";
2022 
2023  try {
2024  preparedStatement = conn.prepareStatement(sql);
2025  preparedStatement.setInt(1, referenceSetID);
2026  preparedStatement.executeUpdate();
2027  } catch (SQLException ex) {
2028  throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2029  } finally {
2030  EamDbUtil.closeStatement(preparedStatement);
2031  EamDbUtil.closeConnection(conn);
2032  }
2033  }
2034 
2043  private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException {
2044  Connection conn = connect();
2045 
2046  PreparedStatement preparedStatement = null;
2047  String sql = "DELETE FROM %s WHERE reference_set_id=?";
2048 
2049  // When other reference types are added, this will need to loop over all the tables
2050  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2051 
2052  try {
2053  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2054  preparedStatement.setInt(1, referenceSetID);
2055  preparedStatement.executeUpdate();
2056  } catch (SQLException ex) {
2057  throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2058  } finally {
2059  EamDbUtil.closeStatement(preparedStatement);
2060  EamDbUtil.closeConnection(conn);
2061  }
2062  }
2063 
2077  @Override
2078  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException {
2079  EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID);
2080  if (refSet == null) {
2081  return false;
2082  }
2083 
2084  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2085  }
2086 
2098  @Override
2099  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException, CorrelationAttributeNormalizationException {
2100  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2101  }
2102 
2112  @Override
2113  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException, CorrelationAttributeNormalizationException {
2114 
2115  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2116 
2117  Connection conn = connect();
2118 
2119  Long matchingInstances = 0L;
2120  PreparedStatement preparedStatement = null;
2121  ResultSet resultSet = null;
2122  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2123 
2124  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2125 
2126  try {
2127  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2128  preparedStatement.setString(1, normalizeValued);
2129  preparedStatement.setInt(2, referenceSetID);
2130  resultSet = preparedStatement.executeQuery();
2131  resultSet.next();
2132  matchingInstances = resultSet.getLong(1);
2133  } catch (SQLException ex) {
2134  throw new EamDbException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2135  } finally {
2136  EamDbUtil.closeStatement(preparedStatement);
2137  EamDbUtil.closeResultSet(resultSet);
2138  EamDbUtil.closeConnection(conn);
2139  }
2140 
2141  return 0 < matchingInstances;
2142  }
2143 
2152  @Override
2153  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
2154 
2155  //this should be done here so that we can be certain that aType and value are valid before we proceed
2156  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2157 
2158  // TEMP: Only support file correlation type
2159  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2160  return false;
2161  }
2162 
2163  Connection conn = connect();
2164 
2165  Long badInstances = 0L;
2166  PreparedStatement preparedStatement = null;
2167  ResultSet resultSet = null;
2168  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2169 
2170  try {
2171  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2172  preparedStatement.setString(1, normalizeValued);
2173  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2174  resultSet = preparedStatement.executeQuery();
2175  resultSet.next();
2176  badInstances = resultSet.getLong(1);
2177  } catch (SQLException ex) {
2178  throw new EamDbException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2179  } finally {
2180  EamDbUtil.closeStatement(preparedStatement);
2181  EamDbUtil.closeResultSet(resultSet);
2182  EamDbUtil.closeConnection(conn);
2183  }
2184 
2185  return 0 < badInstances;
2186  }
2187 
2196  @Override
2197  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
2198  if (type == null) {
2199  throw new EamDbException("Correlation type is null");
2200  }
2201 
2202  if (instanceTableCallback == null) {
2203  throw new EamDbException("Callback interface is null");
2204  }
2205 
2206  Connection conn = connect();
2207  PreparedStatement preparedStatement = null;
2208  ResultSet resultSet = null;
2209  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2210  StringBuilder sql = new StringBuilder();
2211  sql.append("select * from ");
2212  sql.append(tableName);
2213 
2214  try {
2215  preparedStatement = conn.prepareStatement(sql.toString());
2216  resultSet = preparedStatement.executeQuery();
2217  instanceTableCallback.process(resultSet);
2218  } catch (SQLException ex) {
2219  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2220  } finally {
2221  EamDbUtil.closeStatement(preparedStatement);
2222  EamDbUtil.closeResultSet(resultSet);
2223  EamDbUtil.closeConnection(conn);
2224  }
2225  }
2226 
2236  @Override
2237  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException {
2238  if (type == null) {
2239  throw new EamDbException("Correlation type is null");
2240  }
2241 
2242  if (instanceTableCallback == null) {
2243  throw new EamDbException("Callback interface is null");
2244  }
2245 
2246  if (whereClause == null) {
2247  throw new EamDbException("Where clause is null");
2248  }
2249 
2250  Connection conn = connect();
2251  PreparedStatement preparedStatement = null;
2252  ResultSet resultSet = null;
2253  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2254  StringBuilder sql = new StringBuilder(300);
2255  sql.append("select * from ")
2256  .append(tableName)
2257  .append(" WHERE ")
2258  .append(whereClause);
2259 
2260  try {
2261  preparedStatement = conn.prepareStatement(sql.toString());
2262  resultSet = preparedStatement.executeQuery();
2263  instanceTableCallback.process(resultSet);
2264  } catch (SQLException ex) {
2265  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2266  } finally {
2267  EamDbUtil.closeStatement(preparedStatement);
2268  EamDbUtil.closeResultSet(resultSet);
2269  EamDbUtil.closeConnection(conn);
2270  }
2271  }
2272 
2281  @Override
2282  public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws EamDbException {
2283 
2284  if (instanceTableCallback == null) {
2285  throw new EamDbException("Callback interface is null");
2286  }
2287 
2288  if (selectClause == null) {
2289  throw new EamDbException("Select clause is null");
2290  }
2291 
2292  Connection conn = connect();
2293  PreparedStatement preparedStatement = null;
2294  ResultSet resultSet = null;
2295  StringBuilder sql = new StringBuilder(300);
2296  sql.append("select ")
2297  .append(selectClause);
2298 
2299  try {
2300  preparedStatement = conn.prepareStatement(sql.toString());
2301  resultSet = preparedStatement.executeQuery();
2302  instanceTableCallback.process(resultSet);
2303  } catch (SQLException ex) {
2304  throw new EamDbException("Error running query", ex);
2305  } finally {
2306  EamDbUtil.closeStatement(preparedStatement);
2307  EamDbUtil.closeResultSet(resultSet);
2308  EamDbUtil.closeConnection(conn);
2309  }
2310  }
2311 
2312  @Override
2313  public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
2314  if (eamOrg == null) {
2315  throw new EamDbException("EamOrganization is null");
2316  } else if (eamOrg.getOrgID() != -1) {
2317  throw new EamDbException("EamOrganization already has an ID");
2318  }
2319 
2320  Connection conn = connect();
2321  ResultSet generatedKeys = null;
2322  PreparedStatement preparedStatement = null;
2323  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2324  + getConflictClause();
2325 
2326  try {
2327  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2328  preparedStatement.setString(1, eamOrg.getName());
2329  preparedStatement.setString(2, eamOrg.getPocName());
2330  preparedStatement.setString(3, eamOrg.getPocEmail());
2331  preparedStatement.setString(4, eamOrg.getPocPhone());
2332 
2333  preparedStatement.executeUpdate();
2334  generatedKeys = preparedStatement.getGeneratedKeys();
2335  if (generatedKeys.next()) {
2336  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2337  return eamOrg;
2338  } else {
2339  throw new SQLException("Creating user failed, no ID obtained.");
2340  }
2341  } catch (SQLException ex) {
2342  throw new EamDbException("Error inserting new organization.", ex); // NON-NLS
2343  } finally {
2344  EamDbUtil.closeStatement(preparedStatement);
2345  EamDbUtil.closeResultSet(generatedKeys);
2346  EamDbUtil.closeConnection(conn);
2347  }
2348  }
2349 
2357  @Override
2358  public List<EamOrganization> getOrganizations() throws EamDbException {
2359  Connection conn = connect();
2360 
2361  List<EamOrganization> orgs = new ArrayList<>();
2362  PreparedStatement preparedStatement = null;
2363  ResultSet resultSet = null;
2364  String sql = "SELECT * FROM organizations";
2365 
2366  try {
2367  preparedStatement = conn.prepareStatement(sql);
2368  resultSet = preparedStatement.executeQuery();
2369  while (resultSet.next()) {
2370  orgs.add(getEamOrganizationFromResultSet(resultSet));
2371  }
2372  return orgs;
2373 
2374  } catch (SQLException ex) {
2375  throw new EamDbException("Error getting all organizations.", ex); // NON-NLS
2376  } finally {
2377  EamDbUtil.closeStatement(preparedStatement);
2378  EamDbUtil.closeResultSet(resultSet);
2379  EamDbUtil.closeConnection(conn);
2380  }
2381  }
2382 
2392  @Override
2393  public EamOrganization getOrganizationByID(int orgID) throws EamDbException {
2394  Connection conn = connect();
2395 
2396  PreparedStatement preparedStatement = null;
2397  ResultSet resultSet = null;
2398  String sql = "SELECT * FROM organizations WHERE id=?";
2399 
2400  try {
2401  preparedStatement = conn.prepareStatement(sql);
2402  preparedStatement.setInt(1, orgID);
2403  resultSet = preparedStatement.executeQuery();
2404  resultSet.next();
2405  return getEamOrganizationFromResultSet(resultSet);
2406 
2407  } catch (SQLException ex) {
2408  throw new EamDbException("Error getting organization by id.", ex); // NON-NLS
2409  } finally {
2410  EamDbUtil.closeStatement(preparedStatement);
2411  EamDbUtil.closeResultSet(resultSet);
2412  EamDbUtil.closeConnection(conn);
2413  }
2414  }
2415 
2425  @Override
2426  public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException {
2427 
2428  EamGlobalSet globalSet = getReferenceSetByID(referenceSetID);
2429  if (globalSet == null) {
2430  throw new EamDbException("Reference set with ID " + referenceSetID + " not found");
2431  }
2432  return (getOrganizationByID(globalSet.getOrgID()));
2433  }
2434 
2442  private void testArgument(EamOrganization org) throws EamDbException {
2443  if (org == null) {
2444  throw new EamDbException("EamOrganization is null");
2445  } else if (org.getOrgID() == -1) {
2446  throw new EamDbException("Organization has -1 row ID");
2447  }
2448  }
2449 
2458  @Override
2459  public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException {
2460  testArgument(updatedOrganization);
2461 
2462  Connection conn = connect();
2463  PreparedStatement preparedStatement = null;
2464  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2465  try {
2466  preparedStatement = conn.prepareStatement(sql);
2467  preparedStatement.setString(1, updatedOrganization.getName());
2468  preparedStatement.setString(2, updatedOrganization.getPocName());
2469  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2470  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2471  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2472  preparedStatement.executeUpdate();
2473  } catch (SQLException ex) {
2474  throw new EamDbException("Error updating organization.", ex); // NON-NLS
2475  } finally {
2476  EamDbUtil.closeStatement(preparedStatement);
2477  EamDbUtil.closeConnection(conn);
2478  }
2479  }
2480 
2481  @Override
2482  public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException {
2483  testArgument(organizationToDelete);
2484 
2485  Connection conn = connect();
2486  PreparedStatement checkIfUsedStatement = null;
2487  ResultSet resultSet = null;
2488  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2489  PreparedStatement deleteOrgStatement = null;
2490  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2491  try {
2492  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2493  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2494  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2495  resultSet = checkIfUsedStatement.executeQuery();
2496  resultSet.next();
2497  if (resultSet.getLong(1) > 0) {
2498  throw new EamDbException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2499  }
2500  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2501  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2502  deleteOrgStatement.executeUpdate();
2503  } catch (SQLException ex) {
2504  throw new EamDbException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2505  } finally {
2506  EamDbUtil.closeStatement(checkIfUsedStatement);
2507  EamDbUtil.closeStatement(deleteOrgStatement);
2508  EamDbUtil.closeResultSet(resultSet);
2509  EamDbUtil.closeConnection(conn);
2510  }
2511  }
2512 
2522  @Override
2523  public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException {
2524  if (eamGlobalSet == null) {
2525  throw new EamDbException("EamGlobalSet is null");
2526  }
2527 
2528  if (eamGlobalSet.getFileKnownStatus() == null) {
2529  throw new EamDbException("File known status on the EamGlobalSet is null");
2530  }
2531 
2532  if (eamGlobalSet.getType() == null) {
2533  throw new EamDbException("Type on the EamGlobalSet is null");
2534  }
2535 
2536  Connection conn = connect();
2537 
2538  PreparedStatement preparedStatement1 = null;
2539  PreparedStatement preparedStatement2 = null;
2540  ResultSet resultSet = null;
2541  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2542  + getConflictClause();
2543  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2544 
2545  try {
2546  preparedStatement1 = conn.prepareStatement(sql1);
2547  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2548  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2549  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2550  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2551  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2552  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2553  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2554 
2555  preparedStatement1.executeUpdate();
2556 
2557  preparedStatement2 = conn.prepareStatement(sql2);
2558  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2559  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2560  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2561  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2562 
2563  resultSet = preparedStatement2.executeQuery();
2564  resultSet.next();
2565  return resultSet.getInt("id");
2566 
2567  } catch (SQLException ex) {
2568  throw new EamDbException("Error inserting new global set.", ex); // NON-NLS
2569  } finally {
2570  EamDbUtil.closeStatement(preparedStatement1);
2571  EamDbUtil.closeStatement(preparedStatement2);
2572  EamDbUtil.closeResultSet(resultSet);
2573  EamDbUtil.closeConnection(conn);
2574  }
2575  }
2576 
2586  @Override
2587  public EamGlobalSet getReferenceSetByID(int referenceSetID) throws EamDbException {
2588  Connection conn = connect();
2589 
2590  PreparedStatement preparedStatement1 = null;
2591  ResultSet resultSet = null;
2592  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2593 
2594  try {
2595  preparedStatement1 = conn.prepareStatement(sql1);
2596  preparedStatement1.setInt(1, referenceSetID);
2597  resultSet = preparedStatement1.executeQuery();
2598  if (resultSet.next()) {
2599  return getEamGlobalSetFromResultSet(resultSet);
2600  } else {
2601  return null;
2602  }
2603 
2604  } catch (SQLException ex) {
2605  throw new EamDbException("Error getting reference set by id.", ex); // NON-NLS
2606  } finally {
2607  EamDbUtil.closeStatement(preparedStatement1);
2608  EamDbUtil.closeResultSet(resultSet);
2609  EamDbUtil.closeConnection(conn);
2610  }
2611  }
2612 
2622  @Override
2623  public List<EamGlobalSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2624 
2625  if (correlationType == null) {
2626  throw new EamDbException("Correlation type is null");
2627  }
2628 
2629  List<EamGlobalSet> results = new ArrayList<>();
2630  Connection conn = connect();
2631 
2632  PreparedStatement preparedStatement1 = null;
2633  ResultSet resultSet = null;
2634  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
2635 
2636  try {
2637  preparedStatement1 = conn.prepareStatement(sql1);
2638  resultSet = preparedStatement1.executeQuery();
2639  while (resultSet.next()) {
2640  results.add(getEamGlobalSetFromResultSet(resultSet));
2641  }
2642 
2643  } catch (SQLException ex) {
2644  throw new EamDbException("Error getting reference sets.", ex); // NON-NLS
2645  } finally {
2646  EamDbUtil.closeStatement(preparedStatement1);
2647  EamDbUtil.closeResultSet(resultSet);
2648  EamDbUtil.closeConnection(conn);
2649  }
2650  return results;
2651  }
2652 
2662  @Override
2663  public void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2664  if (eamGlobalFileInstance.getKnownStatus() == null) {
2665  throw new EamDbException("Known status of EamGlobalFileInstance is null");
2666  }
2667  if (correlationType == null) {
2668  throw new EamDbException("Correlation type is null");
2669  }
2670 
2671  Connection conn = connect();
2672 
2673  PreparedStatement preparedStatement = null;
2674 
2675  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2676  + getConflictClause();
2677 
2678  try {
2679  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(correlationType)));
2680  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
2681  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
2682  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
2683  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
2684  preparedStatement.executeUpdate();
2685  } catch (SQLException ex) {
2686  throw new EamDbException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
2687  } finally {
2688  EamDbUtil.closeStatement(preparedStatement);
2689  EamDbUtil.closeConnection(conn);
2690  }
2691  }
2692 
2705  @Override
2706  public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException {
2707  Connection conn = connect();
2708 
2709  PreparedStatement preparedStatement1 = null;
2710  ResultSet resultSet = null;
2711  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
2712 
2713  try {
2714  preparedStatement1 = conn.prepareStatement(sql1);
2715  preparedStatement1.setString(1, referenceSetName);
2716  preparedStatement1.setString(2, version);
2717  resultSet = preparedStatement1.executeQuery();
2718  return (resultSet.next());
2719 
2720  } catch (SQLException ex) {
2721  throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName
2722  + " version: " + version, ex); // NON-NLS
2723  } finally {
2724  EamDbUtil.closeStatement(preparedStatement1);
2725  EamDbUtil.closeResultSet(resultSet);
2726  EamDbUtil.closeConnection(conn);
2727  }
2728  }
2729 
2735  @Override
2736  public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws EamDbException {
2737  if (contentType == null) {
2738  throw new EamDbException("Correlation type is null");
2739  }
2740  if (globalInstances == null) {
2741  throw new EamDbException("Null set of EamGlobalFileInstance");
2742  }
2743 
2744  Connection conn = connect();
2745 
2746  PreparedStatement bulkPs = null;
2747  try {
2748  conn.setAutoCommit(false);
2749 
2750  // FUTURE: have a separate global_files table for each Type.
2751  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2752  + getConflictClause();
2753 
2754  bulkPs = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(contentType)));
2755 
2756  for (EamGlobalFileInstance globalInstance : globalInstances) {
2757  if (globalInstance.getKnownStatus() == null) {
2758  throw new EamDbException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
2759  }
2760 
2761  bulkPs.setInt(1, globalInstance.getGlobalSetID());
2762  bulkPs.setString(2, globalInstance.getMD5Hash());
2763  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
2764  bulkPs.setString(4, globalInstance.getComment());
2765  bulkPs.addBatch();
2766  }
2767 
2768  bulkPs.executeBatch();
2769  conn.commit();
2770  } catch (SQLException | EamDbException ex) {
2771  try {
2772  conn.rollback();
2773  } catch (SQLException ex2) {
2774  // We're alredy in an error state
2775  }
2776  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
2777  } finally {
2778  EamDbUtil.closeStatement(bulkPs);
2779  EamDbUtil.closeConnection(conn);
2780  }
2781  }
2782 
2793  @Override
2794  public List<EamGlobalFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws EamDbException, CorrelationAttributeNormalizationException {
2795  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
2796 
2797  Connection conn = connect();
2798 
2799  List<EamGlobalFileInstance> globalFileInstances = new ArrayList<>();
2800  PreparedStatement preparedStatement1 = null;
2801  ResultSet resultSet = null;
2802  String sql1 = "SELECT * FROM %s WHERE value=?";
2803 
2804  try {
2805  preparedStatement1 = conn.prepareStatement(String.format(sql1, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2806  preparedStatement1.setString(1, normalizeValued);
2807  resultSet = preparedStatement1.executeQuery();
2808  while (resultSet.next()) {
2809  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
2810  }
2811 
2812  } catch (SQLException ex) {
2813  throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS
2814  } finally {
2815  EamDbUtil.closeStatement(preparedStatement1);
2816  EamDbUtil.closeResultSet(resultSet);
2817  EamDbUtil.closeConnection(conn);
2818  }
2819 
2820  return globalFileInstances;
2821  }
2822 
2832  @Override
2833  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws EamDbException {
2834  if (newType == null) {
2835  throw new EamDbException("Correlation type is null");
2836  }
2837  int typeId;
2838  if (-1 == newType.getId()) {
2839  typeId = newCorrelationTypeNotKnownId(newType);
2840  } else {
2841  typeId = newCorrelationTypeKnownId(newType);
2842  }
2843 
2844  return typeId;
2845  }
2846 
2857  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
2858  Connection conn = connect();
2859 
2860  PreparedStatement preparedStatement = null;
2861  PreparedStatement preparedStatementQuery = null;
2862  ResultSet resultSet = null;
2863  int typeId = 0;
2864  String insertSql;
2865  String querySql;
2866  // if we have a known ID, use it, if not (is -1) let the db assign it.
2867  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
2868 
2869  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2870 
2871  try {
2872  preparedStatement = conn.prepareStatement(insertSql);
2873 
2874  preparedStatement.setString(1, newType.getDisplayName());
2875  preparedStatement.setString(2, newType.getDbTableName());
2876  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
2877  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
2878 
2879  preparedStatement.executeUpdate();
2880 
2881  preparedStatementQuery = conn.prepareStatement(querySql);
2882  preparedStatementQuery.setString(1, newType.getDisplayName());
2883  preparedStatementQuery.setString(2, newType.getDbTableName());
2884 
2885  resultSet = preparedStatementQuery.executeQuery();
2886  if (resultSet.next()) {
2887  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2888  typeId = correlationType.getId();
2889  }
2890  } catch (SQLException ex) {
2891  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2892  } finally {
2893  EamDbUtil.closeStatement(preparedStatement);
2894  EamDbUtil.closeStatement(preparedStatementQuery);
2895  EamDbUtil.closeResultSet(resultSet);
2896  EamDbUtil.closeConnection(conn);
2897  }
2898  return typeId;
2899  }
2900 
2910  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
2911  Connection conn = connect();
2912 
2913  PreparedStatement preparedStatement = null;
2914  PreparedStatement preparedStatementQuery = null;
2915  ResultSet resultSet = null;
2916  int typeId = 0;
2917  String insertSql;
2918  String querySql;
2919  // if we have a known ID, use it, if not (is -1) let the db assign it.
2920  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
2921 
2922  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2923 
2924  try {
2925  preparedStatement = conn.prepareStatement(insertSql);
2926 
2927  preparedStatement.setInt(1, newType.getId());
2928  preparedStatement.setString(2, newType.getDisplayName());
2929  preparedStatement.setString(3, newType.getDbTableName());
2930  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
2931  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
2932 
2933  preparedStatement.executeUpdate();
2934 
2935  preparedStatementQuery = conn.prepareStatement(querySql);
2936  preparedStatementQuery.setString(1, newType.getDisplayName());
2937  preparedStatementQuery.setString(2, newType.getDbTableName());
2938 
2939  resultSet = preparedStatementQuery.executeQuery();
2940  if (resultSet.next()) {
2941  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2942  typeId = correlationType.getId();
2943  }
2944  } catch (SQLException ex) {
2945  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2946  } finally {
2947  EamDbUtil.closeStatement(preparedStatement);
2948  EamDbUtil.closeStatement(preparedStatementQuery);
2949  EamDbUtil.closeResultSet(resultSet);
2950  EamDbUtil.closeConnection(conn);
2951  }
2952  return typeId;
2953  }
2954 
2955  @Override
2956  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws EamDbException {
2957  Connection conn = connect();
2958 
2959  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
2960  PreparedStatement preparedStatement = null;
2961  ResultSet resultSet = null;
2962  String sql = "SELECT * FROM correlation_types";
2963 
2964  try {
2965  preparedStatement = conn.prepareStatement(sql);
2966  resultSet = preparedStatement.executeQuery();
2967  while (resultSet.next()) {
2968  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2969  }
2970  return aTypes;
2971 
2972  } catch (SQLException ex) {
2973  throw new EamDbException("Error getting all correlation types.", ex); // NON-NLS
2974  } finally {
2975  EamDbUtil.closeStatement(preparedStatement);
2976  EamDbUtil.closeResultSet(resultSet);
2977  EamDbUtil.closeConnection(conn);
2978  }
2979  }
2980 
2990  @Override
2991  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws EamDbException {
2992  Connection conn = connect();
2993 
2994  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
2995  PreparedStatement preparedStatement = null;
2996  ResultSet resultSet = null;
2997  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
2998 
2999  try {
3000  preparedStatement = conn.prepareStatement(sql);
3001  resultSet = preparedStatement.executeQuery();
3002  while (resultSet.next()) {
3003  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3004  }
3005  return aTypes;
3006 
3007  } catch (SQLException ex) {
3008  throw new EamDbException("Error getting enabled correlation types.", ex); // NON-NLS
3009  } finally {
3010  EamDbUtil.closeStatement(preparedStatement);
3011  EamDbUtil.closeResultSet(resultSet);
3012  EamDbUtil.closeConnection(conn);
3013  }
3014  }
3015 
3025  @Override
3026  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws EamDbException {
3027  Connection conn = connect();
3028 
3029  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3030  PreparedStatement preparedStatement = null;
3031  ResultSet resultSet = null;
3032  String sql = "SELECT * FROM correlation_types WHERE supported=1";
3033 
3034  try {
3035  preparedStatement = conn.prepareStatement(sql);
3036  resultSet = preparedStatement.executeQuery();
3037  while (resultSet.next()) {
3038  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3039  }
3040  return aTypes;
3041 
3042  } catch (SQLException ex) {
3043  throw new EamDbException("Error getting supported correlation types.", ex); // NON-NLS
3044  } finally {
3045  EamDbUtil.closeStatement(preparedStatement);
3046  EamDbUtil.closeResultSet(resultSet);
3047  EamDbUtil.closeConnection(conn);
3048  }
3049  }
3050 
3058  @Override
3059  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws EamDbException {
3060  Connection conn = connect();
3061 
3062  PreparedStatement preparedStatement = null;
3063  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3064 
3065  try {
3066  preparedStatement = conn.prepareStatement(sql);
3067  preparedStatement.setString(1, aType.getDisplayName());
3068  preparedStatement.setString(2, aType.getDbTableName());
3069  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3070  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3071  preparedStatement.setInt(5, aType.getId());
3072  preparedStatement.executeUpdate();
3073  typeCache.put(aType.getId(), aType);
3074  } catch (SQLException ex) {
3075  throw new EamDbException("Error updating correlation type.", ex); // NON-NLS
3076  } finally {
3077  EamDbUtil.closeStatement(preparedStatement);
3078  EamDbUtil.closeConnection(conn);
3079  }
3080 
3081  }
3082 
3092  @Override
3093  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws EamDbException {
3094  try {
3095  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3096  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3097  //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
3098  return null;
3099  } catch (ExecutionException ex) {
3100  throw new EamDbException("Error getting correlation type", ex);
3101  }
3102  }
3103 
3113  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws EamDbException {
3114  Connection conn = connect();
3115 
3117  PreparedStatement preparedStatement = null;
3118  ResultSet resultSet = null;
3119  String sql = "SELECT * FROM correlation_types WHERE id=?";
3120 
3121  try {
3122  preparedStatement = conn.prepareStatement(sql);
3123  preparedStatement.setInt(1, typeId);
3124  resultSet = preparedStatement.executeQuery();
3125  if (resultSet.next()) {
3126  aType = getCorrelationTypeFromResultSet(resultSet);
3127  return aType;
3128  } else {
3129  throw new EamDbException("Failed to find entry for correlation type ID = " + typeId);
3130  }
3131 
3132  } catch (SQLException ex) {
3133  throw new EamDbException("Error getting correlation type by id.", ex); // NON-NLS
3134  } finally {
3135  EamDbUtil.closeStatement(preparedStatement);
3136  EamDbUtil.closeResultSet(resultSet);
3137  EamDbUtil.closeConnection(conn);
3138  }
3139  }
3140 
3151  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3152  if (null == resultSet) {
3153  return null;
3154  }
3155 
3156  EamOrganization eamOrg = null;
3157 
3158  resultSet.getInt("org_id");
3159  if (!resultSet.wasNull()) {
3160 
3161  eamOrg = new EamOrganization(resultSet.getInt("org_id"),
3162  resultSet.getString("org_name"),
3163  resultSet.getString("poc_name"),
3164  resultSet.getString("poc_email"),
3165  resultSet.getString("poc_phone"));
3166  }
3167 
3168  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3169  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3170  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3171 
3172  return eamCase;
3173  }
3174 
3175  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3176  if (null == resultSet) {
3177  return null;
3178  }
3179 
3180  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3181  resultSet.getInt("case_id"),
3182  resultSet.getInt("id"),
3183  resultSet.getString("device_id"),
3184  resultSet.getString("name"),
3185  resultSet.getLong("datasource_obj_id"),
3186  resultSet.getString("md5"),
3187  resultSet.getString("sha1"),
3188  resultSet.getString("sha256")
3189  );
3190 
3191  return eamDataSource;
3192  }
3193 
3194  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws EamDbException, SQLException {
3195  if (null == resultSet) {
3196  return null;
3197  }
3198 
3200  resultSet.getInt("id"),
3201  resultSet.getString("display_name"),
3202  resultSet.getString("db_table_name"),
3203  resultSet.getBoolean("supported"),
3204  resultSet.getBoolean("enabled")
3205  );
3206 
3207  return eamArtifactType;
3208  }
3209 
3220  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3221  if (null == resultSet) {
3222  return null;
3223  }
3224 
3225  EamOrganization eamOrg = new EamOrganization(resultSet.getInt("org_id"),
3226  resultSet.getString("org_name"),
3227  resultSet.getString("poc_name"),
3228  resultSet.getString("poc_email"),
3229  resultSet.getString("poc_phone"));
3230 
3231  return new CorrelationAttributeInstance(
3232  aType,
3233  resultSet.getString("value"),
3234  resultSet.getInt("instance_id"),
3235  new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3236  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3237  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3239  resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3240  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3241  resultSet.getString("file_path"),
3242  resultSet.getString("comment"),
3243  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3244  resultSet.getLong("file_obj_id"));
3245  }
3246 
3247  private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3248  if (null == resultSet) {
3249  return null;
3250  }
3251 
3252  return new EamOrganization(
3253  resultSet.getInt("id"),
3254  resultSet.getString("org_name"),
3255  resultSet.getString("poc_name"),
3256  resultSet.getString("poc_email"),
3257  resultSet.getString("poc_phone")
3258  );
3259  }
3260 
3261  private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
3262  if (null == resultSet) {
3263  return null;
3264  }
3265 
3266  return new EamGlobalSet(
3267  resultSet.getInt("id"),
3268  resultSet.getInt("org_id"),
3269  resultSet.getString("set_name"),
3270  resultSet.getString("version"),
3271  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3272  resultSet.getBoolean("read_only"),
3273  EamDb.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3274  LocalDate.parse(resultSet.getString("import_date"))
3275  );
3276  }
3277 
3278  private EamGlobalFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3279  if (null == resultSet) {
3280  return null;
3281  }
3282 
3283  return new EamGlobalFileInstance(
3284  resultSet.getInt("id"),
3285  resultSet.getInt("reference_set_id"),
3286  resultSet.getString("value"),
3287  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3288  resultSet.getString("comment")
3289  );
3290  }
3291 
3302  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3303 
3309  @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.",
3310  "# {0} - minorVersion",
3311  "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
3312  "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
3313  "# {0} - majorVersion",
3314  "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
3315  "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
3316  "# {0} - platformName",
3317  "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
3318  @Override
3319  public void upgradeSchema() throws EamDbException, SQLException, IncompatibleCentralRepoException {
3320 
3321  ResultSet resultSet = null;
3322  Statement statement = null;
3323  PreparedStatement preparedStatement = null;
3324  Connection conn = null;
3325  EamDbPlatformEnum selectedPlatform = null;
3326  try {
3327 
3328  conn = connect(false);
3329  conn.setAutoCommit(false);
3330  statement = conn.createStatement();
3331  selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
3332  int minorVersion = 0;
3333  String minorVersionStr = null;
3334  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "'");
3335  if (resultSet.next()) {
3336  minorVersionStr = resultSet.getString("value");
3337  try {
3338  minorVersion = Integer.parseInt(minorVersionStr);
3339  } catch (NumberFormatException ex) {
3340  throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
3341  }
3342  } else {
3343  throw new EamDbException("Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
3344  }
3345 
3346  int majorVersion = 0;
3347  String majorVersionStr = null;
3348  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "'");
3349  if (resultSet.next()) {
3350  majorVersionStr = resultSet.getString("value");
3351  try {
3352  majorVersion = Integer.parseInt(majorVersionStr);
3353  } catch (NumberFormatException ex) {
3354  throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
3355  }
3356  } else {
3357  throw new EamDbException("Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
3358  }
3359 
3360  /*
3361  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3362  * 4.10.0. The consequence of the bug is that the schema version
3363  * number is always reset to 1.0 or 1.1 if a Central Repository is
3364  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3365  * there is an effort in updates to 1.2 and greater to not retry
3366  * schema updates that may already have been done once.
3367  */
3368  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3369 
3370  //compare the major versions for compatability
3371  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3372  //because it is specific to case db schema versions only supporting major versions greater than 1
3373  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3374  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3375  }
3376  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3377  logger.log(Level.INFO, "Central Repository is up to date");
3378  return;
3379  }
3380  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3381  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3382  return;
3383  }
3384 
3385  /*
3386  * Update to 1.1
3387  */
3388  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3389  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3390  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3391  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3392 
3393  // There's an outide chance that the user has already made an organization with the default name,
3394  // and the default org being missing will not impact any database operations, so continue on
3395  // regardless of whether this succeeds.
3396  EamDbUtil.insertDefaultOrganization(conn);
3397  }
3398 
3399  /*
3400  * Update to 1.2
3401  */
3402  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3403  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3404  final String addSsidTableTemplate;
3405  final String addCaseIdIndexTemplate;
3406  final String addDataSourceIdIndexTemplate;
3407  final String addValueIndexTemplate;
3408  final String addKnownStatusIndexTemplate;
3409  final String addObjectIdIndexTemplate;
3410 
3411  final String addAttributeSql;
3412  //get the data base specific code for creating a new _instance table
3413  switch (selectedPlatform) {
3414  case POSTGRESQL:
3415  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3416 
3417  addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
3418  addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
3419  addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
3420  addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
3421  addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
3422  addObjectIdIndexTemplate = PostgresEamDbSettings.getAddObjectIdIndexTemplate();
3423  break;
3424  case SQLITE:
3425  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3426 
3427  addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
3428  addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
3429  addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
3430  addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
3431  addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
3432  addObjectIdIndexTemplate = SqliteEamDbSettings.getAddObjectIdIndexTemplate();
3433  break;
3434  default:
3435  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3436  }
3437  final String dataSourcesTableName = "data_sources";
3438  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3439  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3440  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3441  }
3442  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3443  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3444  List<String> instaceTablesToAdd = new ArrayList<>();
3445  //update central repository to be able to store new correlation attributes
3446  final String wirelessNetworksDbTableName = "wireless_networks";
3447  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3448  final String macAddressDbTableName = "mac_address";
3449  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3450  final String imeiNumberDbTableName = "imei_number";
3451  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3452  final String iccidNumberDbTableName = "iccid_number";
3453  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3454  final String imsiNumberDbTableName = "imsi_number";
3455  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3456 
3457  //add the wireless_networks attribute to the correlation_types table
3458  preparedStatement = conn.prepareStatement(addAttributeSql);
3459  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3460  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3461  preparedStatement.setString(3, wirelessNetworksDbTableName);
3462  preparedStatement.setInt(4, 1);
3463  preparedStatement.setInt(5, 1);
3464  preparedStatement.execute();
3465 
3466  //add the mac_address attribute to the correlation_types table
3467  preparedStatement = conn.prepareStatement(addAttributeSql);
3468  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3469  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3470  preparedStatement.setString(3, macAddressDbTableName);
3471  preparedStatement.setInt(4, 1);
3472  preparedStatement.setInt(5, 1);
3473  preparedStatement.execute();
3474 
3475  //add the imei_number attribute to the correlation_types table
3476  preparedStatement = conn.prepareStatement(addAttributeSql);
3477  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3478  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3479  preparedStatement.setString(3, imeiNumberDbTableName);
3480  preparedStatement.setInt(4, 1);
3481  preparedStatement.setInt(5, 1);
3482  preparedStatement.execute();
3483 
3484  //add the imsi_number attribute to the correlation_types table
3485  preparedStatement = conn.prepareStatement(addAttributeSql);
3486  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3487  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3488  preparedStatement.setString(3, imsiNumberDbTableName);
3489  preparedStatement.setInt(4, 1);
3490  preparedStatement.setInt(5, 1);
3491  preparedStatement.execute();
3492 
3493  //add the iccid_number attribute to the correlation_types table
3494  preparedStatement = conn.prepareStatement(addAttributeSql);
3495  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3496  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3497  preparedStatement.setString(3, iccidNumberDbTableName);
3498  preparedStatement.setInt(4, 1);
3499  preparedStatement.setInt(5, 1);
3500  preparedStatement.execute();
3501 
3502  //create a new _instances tables and add indexes for their columns
3503  for (String tableName : instaceTablesToAdd) {
3504  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3505  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3506  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3507  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3508  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3509  }
3510 
3511  //add file_obj_id column to _instances table which do not already have it
3512  String instance_type_dbname;
3513  final String objectIdColumnName = "file_obj_id";
3515  instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
3516  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3517  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3518  }
3519  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3520  }
3521 
3522  /*
3523  * Add hash columns to the data_sources table.
3524  */
3525  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3526  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3527  }
3528  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3529  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3530  }
3531  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3532  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3533  }
3534 
3535  /*
3536  * Drop the db_info table and add it back in with the name
3537  * column having a UNIQUE constraint. The name column could now
3538  * be used as the primary key, but the essentially useless id
3539  * column is retained for the sake of backwards compatibility.
3540  * Note that the creation schema version number is set to 0.0 to
3541  * indicate that it is unknown.
3542  */
3543  String creationMajorVer;
3544  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3545  if (resultSet.next()) {
3546  creationMajorVer = resultSet.getString("value");
3547  } else {
3548  creationMajorVer = "0";
3549  }
3550  String creationMinorVer;
3551  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3552  if (resultSet.next()) {
3553  creationMinorVer = resultSet.getString("value");
3554  } else {
3555  creationMinorVer = "0";
3556  }
3557  statement.execute("DROP TABLE db_info");
3558  if (selectedPlatform == EamDbPlatformEnum.POSTGRESQL) {
3559  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3560  } else {
3561  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3562  }
3563  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3564  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3565  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3566  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3567  }
3568  /*
3569  * Update to 1.3
3570  */
3571  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3572  switch (selectedPlatform) {
3573  case POSTGRESQL:
3574  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3575  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3576  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
3577 
3578  break;
3579  case SQLITE:
3580  statement.execute("DROP INDEX IF EXISTS data_sources_name");
3581  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
3582  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
3583  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3584  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
3585  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
3586  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
3587  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
3588  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
3589  statement.execute(SqliteEamDbSettings.getAddDataSourcesNameIndexStatement());
3590  statement.execute(SqliteEamDbSettings.getAddDataSourcesObjectIdIndexStatement());
3591  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
3592  statement.execute("DROP TABLE old_data_sources");
3593  break;
3594  default:
3595  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3596  }
3597  }
3598  updateSchemaVersion(conn);
3599  conn.commit();
3600  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
3601  } catch (SQLException | EamDbException ex) {
3602  try {
3603  if (conn != null) {
3604  conn.rollback();
3605  }
3606  } catch (SQLException ex2) {
3607  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
3608  }
3609  throw ex;
3610  } finally {
3611  EamDbUtil.closeResultSet(resultSet);
3612  EamDbUtil.closeStatement(preparedStatement);
3613  EamDbUtil.closeStatement(statement);
3614  EamDbUtil.closeConnection(conn);
3615  }
3616  }
3617 
3618 }
static String correlationTypeToInstanceTableName(CorrelationAttributeInstance.Type type)
Definition: EamDbUtil.java:354
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:365

Copyright © 2012-2019 Basis Technology. Generated on: Tue Jan 7 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.