Autopsy  4.11.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 
1952  @Override
1953  public void deleteReferenceSet(int referenceSetID) throws EamDbException {
1954  deleteReferenceSetEntries(referenceSetID);
1955  deleteReferenceSetEntry(referenceSetID);
1956  }
1957 
1965  private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException {
1966  Connection conn = connect();
1967 
1968  PreparedStatement preparedStatement = null;
1969  String sql = "DELETE FROM reference_sets WHERE id=?";
1970 
1971  try {
1972  preparedStatement = conn.prepareStatement(sql);
1973  preparedStatement.setInt(1, referenceSetID);
1974  preparedStatement.executeUpdate();
1975  } catch (SQLException ex) {
1976  throw new EamDbException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
1977  } finally {
1978  EamDbUtil.closeStatement(preparedStatement);
1979  EamDbUtil.closeConnection(conn);
1980  }
1981  }
1982 
1991  private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException {
1992  Connection conn = connect();
1993 
1994  PreparedStatement preparedStatement = null;
1995  String sql = "DELETE FROM %s WHERE reference_set_id=?";
1996 
1997  // When other reference types are added, this will need to loop over all the tables
1998  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
1999 
2000  try {
2001  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2002  preparedStatement.setInt(1, referenceSetID);
2003  preparedStatement.executeUpdate();
2004  } catch (SQLException ex) {
2005  throw new EamDbException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2006  } finally {
2007  EamDbUtil.closeStatement(preparedStatement);
2008  EamDbUtil.closeConnection(conn);
2009  }
2010  }
2011 
2025  @Override
2026  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException {
2027  EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID);
2028  if (refSet == null) {
2029  return false;
2030  }
2031 
2032  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2033  }
2034 
2046  @Override
2047  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException, CorrelationAttributeNormalizationException {
2048  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2049  }
2050 
2060  @Override
2061  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException, CorrelationAttributeNormalizationException {
2062 
2063  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2064 
2065  Connection conn = connect();
2066 
2067  Long matchingInstances = 0L;
2068  PreparedStatement preparedStatement = null;
2069  ResultSet resultSet = null;
2070  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2071 
2072  String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2073 
2074  try {
2075  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2076  preparedStatement.setString(1, normalizeValued);
2077  preparedStatement.setInt(2, referenceSetID);
2078  resultSet = preparedStatement.executeQuery();
2079  resultSet.next();
2080  matchingInstances = resultSet.getLong(1);
2081  } catch (SQLException ex) {
2082  throw new EamDbException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2083  } finally {
2084  EamDbUtil.closeStatement(preparedStatement);
2085  EamDbUtil.closeResultSet(resultSet);
2086  EamDbUtil.closeConnection(conn);
2087  }
2088 
2089  return 0 < matchingInstances;
2090  }
2091 
2100  @Override
2101  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
2102 
2103  //this should be done here so that we can be certain that aType and value are valid before we proceed
2104  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2105 
2106  // TEMP: Only support file correlation type
2107  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2108  return false;
2109  }
2110 
2111  Connection conn = connect();
2112 
2113  Long badInstances = 0L;
2114  PreparedStatement preparedStatement = null;
2115  ResultSet resultSet = null;
2116  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2117 
2118  try {
2119  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2120  preparedStatement.setString(1, normalizeValued);
2121  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2122  resultSet = preparedStatement.executeQuery();
2123  resultSet.next();
2124  badInstances = resultSet.getLong(1);
2125  } catch (SQLException ex) {
2126  throw new EamDbException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2127  } finally {
2128  EamDbUtil.closeStatement(preparedStatement);
2129  EamDbUtil.closeResultSet(resultSet);
2130  EamDbUtil.closeConnection(conn);
2131  }
2132 
2133  return 0 < badInstances;
2134  }
2135 
2144  @Override
2145  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException {
2146  if (type == null) {
2147  throw new EamDbException("Correlation type is null");
2148  }
2149 
2150  if (instanceTableCallback == null) {
2151  throw new EamDbException("Callback interface is null");
2152  }
2153 
2154  Connection conn = connect();
2155  PreparedStatement preparedStatement = null;
2156  ResultSet resultSet = null;
2157  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2158  StringBuilder sql = new StringBuilder();
2159  sql.append("select * from ");
2160  sql.append(tableName);
2161 
2162  try {
2163  preparedStatement = conn.prepareStatement(sql.toString());
2164  resultSet = preparedStatement.executeQuery();
2165  instanceTableCallback.process(resultSet);
2166  } catch (SQLException ex) {
2167  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2168  } finally {
2169  EamDbUtil.closeStatement(preparedStatement);
2170  EamDbUtil.closeResultSet(resultSet);
2171  EamDbUtil.closeConnection(conn);
2172  }
2173  }
2174 
2184  @Override
2185  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException {
2186  if (type == null) {
2187  throw new EamDbException("Correlation type is null");
2188  }
2189 
2190  if (instanceTableCallback == null) {
2191  throw new EamDbException("Callback interface is null");
2192  }
2193 
2194  if (whereClause == null) {
2195  throw new EamDbException("Where clause is null");
2196  }
2197 
2198  Connection conn = connect();
2199  PreparedStatement preparedStatement = null;
2200  ResultSet resultSet = null;
2201  String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
2202  StringBuilder sql = new StringBuilder(300);
2203  sql.append("select * from ")
2204  .append(tableName)
2205  .append(" WHERE ")
2206  .append(whereClause);
2207 
2208  try {
2209  preparedStatement = conn.prepareStatement(sql.toString());
2210  resultSet = preparedStatement.executeQuery();
2211  instanceTableCallback.process(resultSet);
2212  } catch (SQLException ex) {
2213  throw new EamDbException("Error getting all artifact instances from instances table", ex);
2214  } finally {
2215  EamDbUtil.closeStatement(preparedStatement);
2216  EamDbUtil.closeResultSet(resultSet);
2217  EamDbUtil.closeConnection(conn);
2218  }
2219  }
2220 
2221  @Override
2222  public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
2223  if (eamOrg == null) {
2224  throw new EamDbException("EamOrganization is null");
2225  } else if (eamOrg.getOrgID() != -1) {
2226  throw new EamDbException("EamOrganization already has an ID");
2227  }
2228 
2229  Connection conn = connect();
2230  ResultSet generatedKeys = null;
2231  PreparedStatement preparedStatement = null;
2232  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2233  + getConflictClause();
2234 
2235  try {
2236  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2237  preparedStatement.setString(1, eamOrg.getName());
2238  preparedStatement.setString(2, eamOrg.getPocName());
2239  preparedStatement.setString(3, eamOrg.getPocEmail());
2240  preparedStatement.setString(4, eamOrg.getPocPhone());
2241 
2242  preparedStatement.executeUpdate();
2243  generatedKeys = preparedStatement.getGeneratedKeys();
2244  if (generatedKeys.next()) {
2245  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2246  return eamOrg;
2247  } else {
2248  throw new SQLException("Creating user failed, no ID obtained.");
2249  }
2250  } catch (SQLException ex) {
2251  throw new EamDbException("Error inserting new organization.", ex); // NON-NLS
2252  } finally {
2253  EamDbUtil.closeStatement(preparedStatement);
2254  EamDbUtil.closeResultSet(generatedKeys);
2255  EamDbUtil.closeConnection(conn);
2256  }
2257  }
2258 
2266  @Override
2267  public List<EamOrganization> getOrganizations() throws EamDbException {
2268  Connection conn = connect();
2269 
2270  List<EamOrganization> orgs = new ArrayList<>();
2271  PreparedStatement preparedStatement = null;
2272  ResultSet resultSet = null;
2273  String sql = "SELECT * FROM organizations";
2274 
2275  try {
2276  preparedStatement = conn.prepareStatement(sql);
2277  resultSet = preparedStatement.executeQuery();
2278  while (resultSet.next()) {
2279  orgs.add(getEamOrganizationFromResultSet(resultSet));
2280  }
2281  return orgs;
2282 
2283  } catch (SQLException ex) {
2284  throw new EamDbException("Error getting all organizations.", ex); // NON-NLS
2285  } finally {
2286  EamDbUtil.closeStatement(preparedStatement);
2287  EamDbUtil.closeResultSet(resultSet);
2288  EamDbUtil.closeConnection(conn);
2289  }
2290  }
2291 
2301  @Override
2302  public EamOrganization getOrganizationByID(int orgID) throws EamDbException {
2303  Connection conn = connect();
2304 
2305  PreparedStatement preparedStatement = null;
2306  ResultSet resultSet = null;
2307  String sql = "SELECT * FROM organizations WHERE id=?";
2308 
2309  try {
2310  preparedStatement = conn.prepareStatement(sql);
2311  preparedStatement.setInt(1, orgID);
2312  resultSet = preparedStatement.executeQuery();
2313  resultSet.next();
2314  return getEamOrganizationFromResultSet(resultSet);
2315 
2316  } catch (SQLException ex) {
2317  throw new EamDbException("Error getting organization by id.", ex); // NON-NLS
2318  } finally {
2319  EamDbUtil.closeStatement(preparedStatement);
2320  EamDbUtil.closeResultSet(resultSet);
2321  EamDbUtil.closeConnection(conn);
2322  }
2323  }
2324 
2334  @Override
2335  public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException {
2336 
2337  EamGlobalSet globalSet = getReferenceSetByID(referenceSetID);
2338  if (globalSet == null) {
2339  throw new EamDbException("Reference set with ID " + referenceSetID + " not found");
2340  }
2341  return (getOrganizationByID(globalSet.getOrgID()));
2342  }
2343 
2351  private void testArgument(EamOrganization org) throws EamDbException {
2352  if (org == null) {
2353  throw new EamDbException("EamOrganization is null");
2354  } else if (org.getOrgID() == -1) {
2355  throw new EamDbException("Organization has -1 row ID");
2356  }
2357  }
2358 
2367  @Override
2368  public void updateOrganization(EamOrganization updatedOrganization) throws EamDbException {
2369  testArgument(updatedOrganization);
2370 
2371  Connection conn = connect();
2372  PreparedStatement preparedStatement = null;
2373  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2374  try {
2375  preparedStatement = conn.prepareStatement(sql);
2376  preparedStatement.setString(1, updatedOrganization.getName());
2377  preparedStatement.setString(2, updatedOrganization.getPocName());
2378  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2379  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2380  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2381  preparedStatement.executeUpdate();
2382  } catch (SQLException ex) {
2383  throw new EamDbException("Error updating organization.", ex); // NON-NLS
2384  } finally {
2385  EamDbUtil.closeStatement(preparedStatement);
2386  EamDbUtil.closeConnection(conn);
2387  }
2388  }
2389 
2390  @Override
2391  public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException {
2392  testArgument(organizationToDelete);
2393 
2394  Connection conn = connect();
2395  PreparedStatement checkIfUsedStatement = null;
2396  ResultSet resultSet = null;
2397  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2398  PreparedStatement deleteOrgStatement = null;
2399  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2400  try {
2401  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2402  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2403  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2404  resultSet = checkIfUsedStatement.executeQuery();
2405  resultSet.next();
2406  if (resultSet.getLong(1) > 0) {
2407  throw new EamDbException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2408  }
2409  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2410  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2411  deleteOrgStatement.executeUpdate();
2412  } catch (SQLException ex) {
2413  throw new EamDbException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2414  } finally {
2415  EamDbUtil.closeStatement(checkIfUsedStatement);
2416  EamDbUtil.closeStatement(deleteOrgStatement);
2417  EamDbUtil.closeResultSet(resultSet);
2418  EamDbUtil.closeConnection(conn);
2419  }
2420  }
2421 
2431  @Override
2432  public int newReferenceSet(EamGlobalSet eamGlobalSet) throws EamDbException {
2433  if (eamGlobalSet == null) {
2434  throw new EamDbException("EamGlobalSet is null");
2435  }
2436 
2437  if (eamGlobalSet.getFileKnownStatus() == null) {
2438  throw new EamDbException("File known status on the EamGlobalSet is null");
2439  }
2440 
2441  if (eamGlobalSet.getType() == null) {
2442  throw new EamDbException("Type on the EamGlobalSet is null");
2443  }
2444 
2445  Connection conn = connect();
2446 
2447  PreparedStatement preparedStatement1 = null;
2448  PreparedStatement preparedStatement2 = null;
2449  ResultSet resultSet = null;
2450  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2451  + getConflictClause();
2452  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2453 
2454  try {
2455  preparedStatement1 = conn.prepareStatement(sql1);
2456  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2457  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2458  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2459  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2460  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2461  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2462  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2463 
2464  preparedStatement1.executeUpdate();
2465 
2466  preparedStatement2 = conn.prepareStatement(sql2);
2467  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2468  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2469  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2470  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2471 
2472  resultSet = preparedStatement2.executeQuery();
2473  resultSet.next();
2474  return resultSet.getInt("id");
2475 
2476  } catch (SQLException ex) {
2477  throw new EamDbException("Error inserting new global set.", ex); // NON-NLS
2478  } finally {
2479  EamDbUtil.closeStatement(preparedStatement1);
2480  EamDbUtil.closeStatement(preparedStatement2);
2481  EamDbUtil.closeResultSet(resultSet);
2482  EamDbUtil.closeConnection(conn);
2483  }
2484  }
2485 
2495  @Override
2496  public EamGlobalSet getReferenceSetByID(int referenceSetID) throws EamDbException {
2497  Connection conn = connect();
2498 
2499  PreparedStatement preparedStatement1 = null;
2500  ResultSet resultSet = null;
2501  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2502 
2503  try {
2504  preparedStatement1 = conn.prepareStatement(sql1);
2505  preparedStatement1.setInt(1, referenceSetID);
2506  resultSet = preparedStatement1.executeQuery();
2507  if (resultSet.next()) {
2508  return getEamGlobalSetFromResultSet(resultSet);
2509  } else {
2510  return null;
2511  }
2512 
2513  } catch (SQLException ex) {
2514  throw new EamDbException("Error getting reference set by id.", ex); // NON-NLS
2515  } finally {
2516  EamDbUtil.closeStatement(preparedStatement1);
2517  EamDbUtil.closeResultSet(resultSet);
2518  EamDbUtil.closeConnection(conn);
2519  }
2520  }
2521 
2531  @Override
2532  public List<EamGlobalSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2533 
2534  if (correlationType == null) {
2535  throw new EamDbException("Correlation type is null");
2536  }
2537 
2538  List<EamGlobalSet> results = new ArrayList<>();
2539  Connection conn = connect();
2540 
2541  PreparedStatement preparedStatement1 = null;
2542  ResultSet resultSet = null;
2543  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
2544 
2545  try {
2546  preparedStatement1 = conn.prepareStatement(sql1);
2547  resultSet = preparedStatement1.executeQuery();
2548  while (resultSet.next()) {
2549  results.add(getEamGlobalSetFromResultSet(resultSet));
2550  }
2551 
2552  } catch (SQLException ex) {
2553  throw new EamDbException("Error getting reference sets.", ex); // NON-NLS
2554  } finally {
2555  EamDbUtil.closeStatement(preparedStatement1);
2556  EamDbUtil.closeResultSet(resultSet);
2557  EamDbUtil.closeConnection(conn);
2558  }
2559  return results;
2560  }
2561 
2571  @Override
2572  public void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws EamDbException {
2573  if (eamGlobalFileInstance.getKnownStatus() == null) {
2574  throw new EamDbException("Known status of EamGlobalFileInstance is null");
2575  }
2576  if (correlationType == null) {
2577  throw new EamDbException("Correlation type is null");
2578  }
2579 
2580  Connection conn = connect();
2581 
2582  PreparedStatement preparedStatement = null;
2583 
2584  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2585  + getConflictClause();
2586 
2587  try {
2588  preparedStatement = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(correlationType)));
2589  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
2590  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
2591  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
2592  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
2593  preparedStatement.executeUpdate();
2594  } catch (SQLException ex) {
2595  throw new EamDbException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
2596  } finally {
2597  EamDbUtil.closeStatement(preparedStatement);
2598  EamDbUtil.closeConnection(conn);
2599  }
2600  }
2601 
2614  @Override
2615  public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException {
2616  Connection conn = connect();
2617 
2618  PreparedStatement preparedStatement1 = null;
2619  ResultSet resultSet = null;
2620  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
2621 
2622  try {
2623  preparedStatement1 = conn.prepareStatement(sql1);
2624  preparedStatement1.setString(1, referenceSetName);
2625  preparedStatement1.setString(2, version);
2626  resultSet = preparedStatement1.executeQuery();
2627  return (resultSet.next());
2628 
2629  } catch (SQLException ex) {
2630  throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName
2631  + " version: " + version, ex); // NON-NLS
2632  } finally {
2633  EamDbUtil.closeStatement(preparedStatement1);
2634  EamDbUtil.closeResultSet(resultSet);
2635  EamDbUtil.closeConnection(conn);
2636  }
2637  }
2638 
2644  @Override
2645  public void bulkInsertReferenceTypeEntries(Set<EamGlobalFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws EamDbException {
2646  if (contentType == null) {
2647  throw new EamDbException("Correlation type is null");
2648  }
2649  if (globalInstances == null) {
2650  throw new EamDbException("Null set of EamGlobalFileInstance");
2651  }
2652 
2653  Connection conn = connect();
2654 
2655  PreparedStatement bulkPs = null;
2656  try {
2657  conn.setAutoCommit(false);
2658 
2659  // FUTURE: have a separate global_files table for each Type.
2660  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
2661  + getConflictClause();
2662 
2663  bulkPs = conn.prepareStatement(String.format(sql, EamDbUtil.correlationTypeToReferenceTableName(contentType)));
2664 
2665  for (EamGlobalFileInstance globalInstance : globalInstances) {
2666  if (globalInstance.getKnownStatus() == null) {
2667  throw new EamDbException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
2668  }
2669 
2670  bulkPs.setInt(1, globalInstance.getGlobalSetID());
2671  bulkPs.setString(2, globalInstance.getMD5Hash());
2672  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
2673  bulkPs.setString(4, globalInstance.getComment());
2674  bulkPs.addBatch();
2675  }
2676 
2677  bulkPs.executeBatch();
2678  conn.commit();
2679  } catch (SQLException | EamDbException ex) {
2680  try {
2681  conn.rollback();
2682  } catch (SQLException ex2) {
2683  // We're alredy in an error state
2684  }
2685  throw new EamDbException("Error inserting bulk artifacts.", ex); // NON-NLS
2686  } finally {
2687  EamDbUtil.closeStatement(bulkPs);
2688  EamDbUtil.closeConnection(conn);
2689  }
2690  }
2691 
2702  @Override
2703  public List<EamGlobalFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws EamDbException, CorrelationAttributeNormalizationException {
2704  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
2705 
2706  Connection conn = connect();
2707 
2708  List<EamGlobalFileInstance> globalFileInstances = new ArrayList<>();
2709  PreparedStatement preparedStatement1 = null;
2710  ResultSet resultSet = null;
2711  String sql1 = "SELECT * FROM %s WHERE value=?";
2712 
2713  try {
2714  preparedStatement1 = conn.prepareStatement(String.format(sql1, EamDbUtil.correlationTypeToReferenceTableName(aType)));
2715  preparedStatement1.setString(1, normalizeValued);
2716  resultSet = preparedStatement1.executeQuery();
2717  while (resultSet.next()) {
2718  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
2719  }
2720 
2721  } catch (SQLException ex) {
2722  throw new EamDbException("Error getting reference instances by type and value.", ex); // NON-NLS
2723  } finally {
2724  EamDbUtil.closeStatement(preparedStatement1);
2725  EamDbUtil.closeResultSet(resultSet);
2726  EamDbUtil.closeConnection(conn);
2727  }
2728 
2729  return globalFileInstances;
2730  }
2731 
2741  @Override
2742  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws EamDbException {
2743  if (newType == null) {
2744  throw new EamDbException("Correlation type is null");
2745  }
2746  int typeId;
2747  if (-1 == newType.getId()) {
2748  typeId = newCorrelationTypeNotKnownId(newType);
2749  } else {
2750  typeId = newCorrelationTypeKnownId(newType);
2751  }
2752 
2753  return typeId;
2754  }
2755 
2766  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
2767  Connection conn = connect();
2768 
2769  PreparedStatement preparedStatement = null;
2770  PreparedStatement preparedStatementQuery = null;
2771  ResultSet resultSet = null;
2772  int typeId = 0;
2773  String insertSql;
2774  String querySql;
2775  // if we have a known ID, use it, if not (is -1) let the db assign it.
2776  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
2777 
2778  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2779 
2780  try {
2781  preparedStatement = conn.prepareStatement(insertSql);
2782 
2783  preparedStatement.setString(1, newType.getDisplayName());
2784  preparedStatement.setString(2, newType.getDbTableName());
2785  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
2786  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
2787 
2788  preparedStatement.executeUpdate();
2789 
2790  preparedStatementQuery = conn.prepareStatement(querySql);
2791  preparedStatementQuery.setString(1, newType.getDisplayName());
2792  preparedStatementQuery.setString(2, newType.getDbTableName());
2793 
2794  resultSet = preparedStatementQuery.executeQuery();
2795  if (resultSet.next()) {
2796  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2797  typeId = correlationType.getId();
2798  }
2799  } catch (SQLException ex) {
2800  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2801  } finally {
2802  EamDbUtil.closeStatement(preparedStatement);
2803  EamDbUtil.closeStatement(preparedStatementQuery);
2804  EamDbUtil.closeResultSet(resultSet);
2805  EamDbUtil.closeConnection(conn);
2806  }
2807  return typeId;
2808  }
2809 
2819  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws EamDbException {
2820  Connection conn = connect();
2821 
2822  PreparedStatement preparedStatement = null;
2823  PreparedStatement preparedStatementQuery = null;
2824  ResultSet resultSet = null;
2825  int typeId = 0;
2826  String insertSql;
2827  String querySql;
2828  // if we have a known ID, use it, if not (is -1) let the db assign it.
2829  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
2830 
2831  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
2832 
2833  try {
2834  preparedStatement = conn.prepareStatement(insertSql);
2835 
2836  preparedStatement.setInt(1, newType.getId());
2837  preparedStatement.setString(2, newType.getDisplayName());
2838  preparedStatement.setString(3, newType.getDbTableName());
2839  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
2840  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
2841 
2842  preparedStatement.executeUpdate();
2843 
2844  preparedStatementQuery = conn.prepareStatement(querySql);
2845  preparedStatementQuery.setString(1, newType.getDisplayName());
2846  preparedStatementQuery.setString(2, newType.getDbTableName());
2847 
2848  resultSet = preparedStatementQuery.executeQuery();
2849  if (resultSet.next()) {
2850  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
2851  typeId = correlationType.getId();
2852  }
2853  } catch (SQLException ex) {
2854  throw new EamDbException("Error inserting new correlation type.", ex); // NON-NLS
2855  } finally {
2856  EamDbUtil.closeStatement(preparedStatement);
2857  EamDbUtil.closeStatement(preparedStatementQuery);
2858  EamDbUtil.closeResultSet(resultSet);
2859  EamDbUtil.closeConnection(conn);
2860  }
2861  return typeId;
2862  }
2863 
2864  @Override
2865  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws EamDbException {
2866  Connection conn = connect();
2867 
2868  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
2869  PreparedStatement preparedStatement = null;
2870  ResultSet resultSet = null;
2871  String sql = "SELECT * FROM correlation_types";
2872 
2873  try {
2874  preparedStatement = conn.prepareStatement(sql);
2875  resultSet = preparedStatement.executeQuery();
2876  while (resultSet.next()) {
2877  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2878  }
2879  return aTypes;
2880 
2881  } catch (SQLException ex) {
2882  throw new EamDbException("Error getting all correlation types.", ex); // NON-NLS
2883  } finally {
2884  EamDbUtil.closeStatement(preparedStatement);
2885  EamDbUtil.closeResultSet(resultSet);
2886  EamDbUtil.closeConnection(conn);
2887  }
2888  }
2889 
2899  @Override
2900  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws EamDbException {
2901  Connection conn = connect();
2902 
2903  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
2904  PreparedStatement preparedStatement = null;
2905  ResultSet resultSet = null;
2906  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
2907 
2908  try {
2909  preparedStatement = conn.prepareStatement(sql);
2910  resultSet = preparedStatement.executeQuery();
2911  while (resultSet.next()) {
2912  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2913  }
2914  return aTypes;
2915 
2916  } catch (SQLException ex) {
2917  throw new EamDbException("Error getting enabled correlation types.", ex); // NON-NLS
2918  } finally {
2919  EamDbUtil.closeStatement(preparedStatement);
2920  EamDbUtil.closeResultSet(resultSet);
2921  EamDbUtil.closeConnection(conn);
2922  }
2923  }
2924 
2934  @Override
2935  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws EamDbException {
2936  Connection conn = connect();
2937 
2938  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
2939  PreparedStatement preparedStatement = null;
2940  ResultSet resultSet = null;
2941  String sql = "SELECT * FROM correlation_types WHERE supported=1";
2942 
2943  try {
2944  preparedStatement = conn.prepareStatement(sql);
2945  resultSet = preparedStatement.executeQuery();
2946  while (resultSet.next()) {
2947  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
2948  }
2949  return aTypes;
2950 
2951  } catch (SQLException ex) {
2952  throw new EamDbException("Error getting supported correlation types.", ex); // NON-NLS
2953  } finally {
2954  EamDbUtil.closeStatement(preparedStatement);
2955  EamDbUtil.closeResultSet(resultSet);
2956  EamDbUtil.closeConnection(conn);
2957  }
2958  }
2959 
2967  @Override
2968  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws EamDbException {
2969  Connection conn = connect();
2970 
2971  PreparedStatement preparedStatement = null;
2972  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
2973 
2974  try {
2975  preparedStatement = conn.prepareStatement(sql);
2976  preparedStatement.setString(1, aType.getDisplayName());
2977  preparedStatement.setString(2, aType.getDbTableName());
2978  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
2979  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
2980  preparedStatement.setInt(5, aType.getId());
2981  preparedStatement.executeUpdate();
2982  typeCache.put(aType.getId(), aType);
2983  } catch (SQLException ex) {
2984  throw new EamDbException("Error updating correlation type.", ex); // NON-NLS
2985  } finally {
2986  EamDbUtil.closeStatement(preparedStatement);
2987  EamDbUtil.closeConnection(conn);
2988  }
2989 
2990  }
2991 
3001  @Override
3002  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws EamDbException {
3003  try {
3004  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3005  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3006  //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
3007  return null;
3008  } catch (ExecutionException ex) {
3009  throw new EamDbException("Error getting correlation type", ex);
3010  }
3011  }
3012 
3022  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws EamDbException {
3023  Connection conn = connect();
3024 
3026  PreparedStatement preparedStatement = null;
3027  ResultSet resultSet = null;
3028  String sql = "SELECT * FROM correlation_types WHERE id=?";
3029 
3030  try {
3031  preparedStatement = conn.prepareStatement(sql);
3032  preparedStatement.setInt(1, typeId);
3033  resultSet = preparedStatement.executeQuery();
3034  if (resultSet.next()) {
3035  aType = getCorrelationTypeFromResultSet(resultSet);
3036  return aType;
3037  } else {
3038  throw new EamDbException("Failed to find entry for correlation type ID = " + typeId);
3039  }
3040 
3041  } catch (SQLException ex) {
3042  throw new EamDbException("Error getting correlation type by id.", ex); // NON-NLS
3043  } finally {
3044  EamDbUtil.closeStatement(preparedStatement);
3045  EamDbUtil.closeResultSet(resultSet);
3046  EamDbUtil.closeConnection(conn);
3047  }
3048  }
3049 
3060  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3061  if (null == resultSet) {
3062  return null;
3063  }
3064 
3065  EamOrganization eamOrg = null;
3066 
3067  resultSet.getInt("org_id");
3068  if (!resultSet.wasNull()) {
3069 
3070  eamOrg = new EamOrganization(resultSet.getInt("org_id"),
3071  resultSet.getString("org_name"),
3072  resultSet.getString("poc_name"),
3073  resultSet.getString("poc_email"),
3074  resultSet.getString("poc_phone"));
3075  }
3076 
3077  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3078  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3079  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3080 
3081  return eamCase;
3082  }
3083 
3084  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3085  if (null == resultSet) {
3086  return null;
3087  }
3088 
3089  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3090  resultSet.getInt("case_id"),
3091  resultSet.getInt("id"),
3092  resultSet.getString("device_id"),
3093  resultSet.getString("name"),
3094  resultSet.getLong("datasource_obj_id"),
3095  resultSet.getString("md5"),
3096  resultSet.getString("sha1"),
3097  resultSet.getString("sha256")
3098  );
3099 
3100  return eamDataSource;
3101  }
3102 
3103  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws EamDbException, SQLException {
3104  if (null == resultSet) {
3105  return null;
3106  }
3107 
3109  resultSet.getInt("id"),
3110  resultSet.getString("display_name"),
3111  resultSet.getString("db_table_name"),
3112  resultSet.getBoolean("supported"),
3113  resultSet.getBoolean("enabled")
3114  );
3115 
3116  return eamArtifactType;
3117  }
3118 
3129  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3130  if (null == resultSet) {
3131  return null;
3132  }
3133 
3134  EamOrganization eamOrg = new EamOrganization(resultSet.getInt("org_id"),
3135  resultSet.getString("org_name"),
3136  resultSet.getString("poc_name"),
3137  resultSet.getString("poc_email"),
3138  resultSet.getString("poc_phone"));
3139 
3140  return new CorrelationAttributeInstance(
3141  aType,
3142  resultSet.getString("value"),
3143  resultSet.getInt("instance_id"),
3144  new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3145  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3146  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3148  resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3149  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3150  resultSet.getString("file_path"),
3151  resultSet.getString("comment"),
3152  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3153  resultSet.getLong("file_obj_id"));
3154  }
3155 
3156  private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3157  if (null == resultSet) {
3158  return null;
3159  }
3160 
3161  return new EamOrganization(
3162  resultSet.getInt("id"),
3163  resultSet.getString("org_name"),
3164  resultSet.getString("poc_name"),
3165  resultSet.getString("poc_email"),
3166  resultSet.getString("poc_phone")
3167  );
3168  }
3169 
3170  private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, EamDbException {
3171  if (null == resultSet) {
3172  return null;
3173  }
3174 
3175  return new EamGlobalSet(
3176  resultSet.getInt("id"),
3177  resultSet.getInt("org_id"),
3178  resultSet.getString("set_name"),
3179  resultSet.getString("version"),
3180  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3181  resultSet.getBoolean("read_only"),
3182  EamDb.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3183  LocalDate.parse(resultSet.getString("import_date"))
3184  );
3185  }
3186 
3187  private EamGlobalFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, EamDbException, CorrelationAttributeNormalizationException {
3188  if (null == resultSet) {
3189  return null;
3190  }
3191 
3192  return new EamGlobalFileInstance(
3193  resultSet.getInt("id"),
3194  resultSet.getInt("reference_set_id"),
3195  resultSet.getString("value"),
3196  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3197  resultSet.getString("comment")
3198  );
3199  }
3200 
3211  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3212 
3218  @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."})
3219  @Override
3220  public void upgradeSchema() throws EamDbException, SQLException, IncompatibleCentralRepoException {
3221 
3222  ResultSet resultSet = null;
3223  Statement statement = null;
3224  PreparedStatement preparedStatement = null;
3225  Connection conn = null;
3226  EamDbPlatformEnum selectedPlatform = null;
3227  try {
3228 
3229  conn = connect(false);
3230  conn.setAutoCommit(false);
3231  statement = conn.createStatement();
3232  selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
3233  int minorVersion = 0;
3234  String minorVersionStr = null;
3235  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "'");
3236  if (resultSet.next()) {
3237  minorVersionStr = resultSet.getString("value");
3238  try {
3239  minorVersion = Integer.parseInt(minorVersionStr);
3240  } catch (NumberFormatException ex) {
3241  throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", ex);
3242  }
3243  } else {
3244  throw new EamDbException("Failed to read schema minor version from db_info table");
3245  }
3246 
3247  int majorVersion = 0;
3248  String majorVersionStr = null;
3249  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "'");
3250  if (resultSet.next()) {
3251  majorVersionStr = resultSet.getString("value");
3252  try {
3253  majorVersion = Integer.parseInt(majorVersionStr);
3254  } catch (NumberFormatException ex) {
3255  throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", ex);
3256  }
3257  } else {
3258  throw new EamDbException("Failed to read schema major version from db_info table");
3259  }
3260 
3261  /*
3262  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3263  * 4.10.0. The consequence of the bug is that the schema version
3264  * number is always reset to 1.0 or 1.1 if a Central Repository is
3265  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3266  * there is an effort in updates to 1.2 and greater to not retry
3267  * schema updates that may already have been done once.
3268  */
3269  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3270 
3271  //compare the major versions for compatability
3272  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3273  //because it is specific to case db schema versions only supporting major versions greater than 1
3274  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3275  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3276  }
3277  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3278  logger.log(Level.INFO, "Central Repository is up to date");
3279  return;
3280  }
3281  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3282  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3283  return;
3284  }
3285 
3286  /*
3287  * Update to 1.1
3288  */
3289  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3290  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3291  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3292  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3293 
3294  // There's an outide chance that the user has already made an organization with the default name,
3295  // and the default org being missing will not impact any database operations, so continue on
3296  // regardless of whether this succeeds.
3297  EamDbUtil.insertDefaultOrganization(conn);
3298  }
3299 
3300  /*
3301  * Update to 1.2
3302  */
3303  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3304  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3305  final String addSsidTableTemplate;
3306  final String addCaseIdIndexTemplate;
3307  final String addDataSourceIdIndexTemplate;
3308  final String addValueIndexTemplate;
3309  final String addKnownStatusIndexTemplate;
3310  final String addObjectIdIndexTemplate;
3311 
3312  final String addAttributeSql;
3313  //get the data base specific code for creating a new _instance table
3314  switch (selectedPlatform) {
3315  case POSTGRESQL:
3316  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3317 
3318  addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
3319  addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
3320  addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
3321  addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
3322  addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
3323  addObjectIdIndexTemplate = PostgresEamDbSettings.getAddObjectIdIndexTemplate();
3324  break;
3325  case SQLITE:
3326  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3327 
3328  addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
3329  addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
3330  addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
3331  addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
3332  addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
3333  addObjectIdIndexTemplate = SqliteEamDbSettings.getAddObjectIdIndexTemplate();
3334  break;
3335  default:
3336  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
3337  }
3338  final String dataSourcesTableName = "data_sources";
3339  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3340  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3341  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3342  }
3343  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3344  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3345  List<String> instaceTablesToAdd = new ArrayList<>();
3346  //update central repository to be able to store new correlation attributes
3347  final String wirelessNetworksDbTableName = "wireless_networks";
3348  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3349  final String macAddressDbTableName = "mac_address";
3350  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3351  final String imeiNumberDbTableName = "imei_number";
3352  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3353  final String iccidNumberDbTableName = "iccid_number";
3354  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3355  final String imsiNumberDbTableName = "imsi_number";
3356  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3357 
3358  //add the wireless_networks attribute to the correlation_types table
3359  preparedStatement = conn.prepareStatement(addAttributeSql);
3360  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3361  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3362  preparedStatement.setString(3, wirelessNetworksDbTableName);
3363  preparedStatement.setInt(4, 1);
3364  preparedStatement.setInt(5, 1);
3365  preparedStatement.execute();
3366 
3367  //add the mac_address attribute to the correlation_types table
3368  preparedStatement = conn.prepareStatement(addAttributeSql);
3369  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3370  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3371  preparedStatement.setString(3, macAddressDbTableName);
3372  preparedStatement.setInt(4, 1);
3373  preparedStatement.setInt(5, 1);
3374  preparedStatement.execute();
3375 
3376  //add the imei_number attribute to the correlation_types table
3377  preparedStatement = conn.prepareStatement(addAttributeSql);
3378  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3379  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3380  preparedStatement.setString(3, imeiNumberDbTableName);
3381  preparedStatement.setInt(4, 1);
3382  preparedStatement.setInt(5, 1);
3383  preparedStatement.execute();
3384 
3385  //add the imsi_number attribute to the correlation_types table
3386  preparedStatement = conn.prepareStatement(addAttributeSql);
3387  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3388  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3389  preparedStatement.setString(3, imsiNumberDbTableName);
3390  preparedStatement.setInt(4, 1);
3391  preparedStatement.setInt(5, 1);
3392  preparedStatement.execute();
3393 
3394  //add the iccid_number attribute to the correlation_types table
3395  preparedStatement = conn.prepareStatement(addAttributeSql);
3396  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3397  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3398  preparedStatement.setString(3, iccidNumberDbTableName);
3399  preparedStatement.setInt(4, 1);
3400  preparedStatement.setInt(5, 1);
3401  preparedStatement.execute();
3402 
3403  //create a new _instances tables and add indexes for their columns
3404  for (String tableName : instaceTablesToAdd) {
3405  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3406  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3407  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3408  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3409  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3410  }
3411 
3412  //add file_obj_id column to _instances table which do not already have it
3413  String instance_type_dbname;
3414  final String objectIdColumnName = "file_obj_id";
3416  instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
3417  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3418  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3419  }
3420  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3421  }
3422 
3423  /*
3424  * Add hash columns to the data_sources table.
3425  */
3426  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3427  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3428  }
3429  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3430  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3431  }
3432  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3433  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3434  }
3435 
3436  /*
3437  * Drop the db_info table and add it back in with the name
3438  * column having a UNIQUE constraint. The name column could now
3439  * be used as the primary key, but the essentially useless id
3440  * column is retained for the sake of backwards compatibility.
3441  * Note that the creation schema version number is set to 0.0 to
3442  * indicate that it is unknown.
3443  */
3444  String creationMajorVer;
3445  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3446  if (resultSet.next()) {
3447  creationMajorVer = resultSet.getString("value");
3448  } else {
3449  creationMajorVer = "0";
3450  }
3451  String creationMinorVer;
3452  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3453  if (resultSet.next()) {
3454  creationMinorVer = resultSet.getString("value");
3455  } else {
3456  creationMinorVer = "0";
3457  }
3458  statement.execute("DROP TABLE db_info");
3459  if (selectedPlatform == EamDbPlatformEnum.POSTGRESQL) {
3460  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3461  } else {
3462  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3463  }
3464  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3465  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3466  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3467  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + AbstractSqlEamDb.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3468  }
3469  /*
3470  * Update to 1.3
3471  */
3472  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3473  switch (selectedPlatform) {
3474  case POSTGRESQL:
3475  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3476  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3477  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
3478 
3479  break;
3480  case SQLITE:
3481  statement.execute("DROP INDEX IF EXISTS data_sources_name");
3482  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
3483  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
3484  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3485  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
3486  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
3487  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
3488  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
3489  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
3490  statement.execute(SqliteEamDbSettings.getAddDataSourcesNameIndexStatement());
3491  statement.execute(SqliteEamDbSettings.getAddDataSourcesObjectIdIndexStatement());
3492  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
3493  statement.execute("DROP TABLE old_data_sources");
3494  break;
3495  default:
3496  throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
3497  }
3498  }
3499  updateSchemaVersion(conn);
3500  conn.commit();
3501  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
3502 
3503  } catch (SQLException | EamDbException ex) {
3504  try {
3505  if (conn != null) {
3506  conn.rollback();
3507  }
3508  } catch (SQLException ex2) {
3509  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
3510  }
3511  throw ex;
3512  } finally {
3513  EamDbUtil.closeResultSet(resultSet);
3514  EamDbUtil.closeStatement(preparedStatement);
3515  EamDbUtil.closeStatement(statement);
3516  EamDbUtil.closeConnection(conn);
3517  }
3518  }
3519 
3520 }
static String correlationTypeToInstanceTableName(CorrelationAttributeInstance.Type type)
Definition: EamDbUtil.java:330
static TimingMetric getTimingMetric(String name)
static String normalize(CorrelationAttributeInstance.Type attributeType, String data)
CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId)
static void submitTimingMetric(TimingMetric metric)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static String correlationTypeToReferenceTableName(CorrelationAttributeInstance.Type type)
Definition: EamDbUtil.java:341

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