Autopsy  4.19.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
RdbmsCentralRepo.java
Go to the documentation of this file.
1 /*
2  * Central Repository
3  *
4  * Copyright 2015-2021 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.Optional;
41 import java.util.Set;
42 import java.util.concurrent.ExecutionException;
43 import java.util.concurrent.TimeUnit;
44 import java.util.logging.Level;
45 import org.apache.commons.lang3.tuple.Pair;
46 import org.openide.util.NbBundle.Messages;
49 import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil.updateSchemaVersion;
53 import org.sleuthkit.datamodel.Account;
54 import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
55 import org.sleuthkit.datamodel.HashHitInfo;
56 import org.sleuthkit.datamodel.InvalidAccountIDException;
57 import org.sleuthkit.datamodel.SleuthkitCase;
58 import org.sleuthkit.datamodel.TskData;
59 
65 abstract class RdbmsCentralRepo implements CentralRepository {
66 
67  private final static Logger logger = Logger.getLogger(RdbmsCentralRepo.class.getName());
68  static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_VERSION";
69  static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
70  static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
71  static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
72  static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 6);
73 
74  protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
75 
76  private int bulkArtifactsCount;
77  protected int bulkArtifactsThreshold;
78  private final Map<String, Collection<CorrelationAttributeInstance>> bulkArtifacts;
79  private static final int CASE_CACHE_TIMEOUT = 5;
80  private static final int DATA_SOURCE_CACHE_TIMEOUT = 5;
81  private static final int ACCOUNTS_CACHE_TIMEOUT = 5;
82  private static final Cache<String, Optional<CentralRepoAccountType>> accountTypesCache = CacheBuilder.newBuilder().build();
83  private static final Cache<Pair<CentralRepoAccountType, String>, CentralRepoAccount> accountsCache = CacheBuilder.newBuilder()
84  .expireAfterWrite(ACCOUNTS_CACHE_TIMEOUT, TimeUnit.MINUTES).
85  build();
86 
87  private boolean isCRTypeCacheInitialized;
88  private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
89  private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
90  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
91  build();
92  private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
93  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
94  build();
95  private static final Cache<String, CorrelationDataSource> dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
96  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
97  build();
98  private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
99  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
100  build();
101  // Maximum length for the value column in the instance tables
102  static final int MAX_VALUE_LENGTH = 256;
103 
104  // number of instances to keep in bulk queue before doing an insert.
105  // Update Test code if this changes. It's hard coded there.
106  static final int DEFAULT_BULK_THRESHHOLD = 1000;
107 
108  private static final int QUERY_STR_MAX_LEN = 1000;
109 
115  protected RdbmsCentralRepo() throws CentralRepoException {
116  isCRTypeCacheInitialized = false;
117  bulkArtifactsCount = 0;
118  bulkArtifacts = new HashMap<>();
119 
120  defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
121  defaultCorrelationTypes.forEach((type) -> {
122  bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(type), new ArrayList<>());
123  });
124  }
125 
129  protected abstract Connection connect(boolean foreignKeys) throws CentralRepoException;
130 
134  protected abstract Connection connect() throws CentralRepoException;
135 
139  protected abstract Connection getEphemeralConnection();
140 
149  @Override
150  public void newDbInfo(String name, String value) throws CentralRepoException {
151  Connection conn = connect();
152 
153  PreparedStatement preparedStatement = null;
154  String sql = "INSERT INTO db_info (name, value) VALUES (?, ?) "
155  + getConflictClause();
156  try {
157  preparedStatement = conn.prepareStatement(sql);
158  preparedStatement.setString(1, name);
159  preparedStatement.setString(2, value);
160  preparedStatement.executeUpdate();
161  } catch (SQLException ex) {
162  throw new CentralRepoException("Error adding new name/value pair to db_info.", ex);
163  } finally {
164  CentralRepoDbUtil.closeStatement(preparedStatement);
165  CentralRepoDbUtil.closeConnection(conn);
166  }
167 
168  }
169 
170  @Override
171  public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws CentralRepoException {
172  Connection conn = connect();
173  PreparedStatement preparedStatement = null;
174  String sql = "UPDATE data_sources SET datasource_obj_id=? WHERE id=?";
175  try {
176  preparedStatement = conn.prepareStatement(sql);
177  preparedStatement.setLong(1, dataSourceObjectId);
178  preparedStatement.setInt(2, rowId);
179  preparedStatement.executeUpdate();
180  } catch (SQLException ex) {
181  throw new CentralRepoException("Error updating data source object id for data_sources row " + rowId, ex);
182  } finally {
183  CentralRepoDbUtil.closeStatement(preparedStatement);
184  CentralRepoDbUtil.closeConnection(conn);
185  }
186  }
187 
197  @Override
198  public String getDbInfo(String name) throws CentralRepoException {
199  Connection conn = connect();
200 
201  PreparedStatement preparedStatement = null;
202  ResultSet resultSet = null;
203  String value = null;
204  String sql = "SELECT value FROM db_info WHERE name=?";
205  try {
206  preparedStatement = conn.prepareStatement(sql);
207  preparedStatement.setString(1, name);
208  resultSet = preparedStatement.executeQuery();
209  if (resultSet.next()) {
210  value = resultSet.getString("value");
211  }
212  } catch (SQLException ex) {
213  throw new CentralRepoException("Error getting value for name.", ex);
214  } finally {
215  CentralRepoDbUtil.closeResultSet(resultSet);
216  CentralRepoDbUtil.closeStatement(preparedStatement);
217  CentralRepoDbUtil.closeConnection(conn);
218  }
219 
220  return value;
221  }
222 
226  public final void clearCaches() {
227  synchronized (typeCache) {
228  typeCache.invalidateAll();
229  isCRTypeCacheInitialized = false;
230  }
231  caseCacheByUUID.invalidateAll();
232  caseCacheById.invalidateAll();
233  dataSourceCacheByDsObjectId.invalidateAll();
234  dataSourceCacheById.invalidateAll();
235  accountsCache.invalidateAll();
236  }
237 
246  @Override
247  public void updateDbInfo(String name, String value) throws CentralRepoException {
248  Connection conn = connect();
249 
250  PreparedStatement preparedStatement = null;
251  String sql = "UPDATE db_info SET value=? WHERE name=?";
252  try {
253  preparedStatement = conn.prepareStatement(sql);
254  preparedStatement.setString(1, value);
255  preparedStatement.setString(2, name);
256  preparedStatement.executeUpdate();
257  } catch (SQLException ex) {
258  throw new CentralRepoException("Error updating value for name.", ex);
259  } finally {
260  CentralRepoDbUtil.closeStatement(preparedStatement);
261  CentralRepoDbUtil.closeConnection(conn);
262  }
263  }
264 
274  @Override
275  public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws CentralRepoException {
276 
277  if (eamCase.getCaseUUID() == null) {
278  throw new CentralRepoException("Case UUID is null");
279  }
280 
281  // check if there is already an existing CorrelationCase for this Case
282  CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
283  if (cRCase != null) {
284  return cRCase;
285  }
286 
287  Connection conn = connect();
288  PreparedStatement preparedStatement = null;
289 
290  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
291  + "examiner_name, examiner_email, examiner_phone, notes) "
292  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
293  + getConflictClause();
294  ResultSet resultSet = null;
295  try {
296  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
297 
298  preparedStatement.setString(1, eamCase.getCaseUUID());
299  if (null == eamCase.getOrg()) {
300  preparedStatement.setNull(2, Types.INTEGER);
301  } else {
302  preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
303  }
304  preparedStatement.setString(3, eamCase.getDisplayName());
305  preparedStatement.setString(4, eamCase.getCreationDate());
306  if ("".equals(eamCase.getCaseNumber())) {
307  preparedStatement.setNull(5, Types.INTEGER);
308  } else {
309  preparedStatement.setString(5, eamCase.getCaseNumber());
310  }
311  if ("".equals(eamCase.getExaminerName())) {
312  preparedStatement.setNull(6, Types.INTEGER);
313  } else {
314  preparedStatement.setString(6, eamCase.getExaminerName());
315  }
316  if ("".equals(eamCase.getExaminerEmail())) {
317  preparedStatement.setNull(7, Types.INTEGER);
318  } else {
319  preparedStatement.setString(7, eamCase.getExaminerEmail());
320  }
321  if ("".equals(eamCase.getExaminerPhone())) {
322  preparedStatement.setNull(8, Types.INTEGER);
323  } else {
324  preparedStatement.setString(8, eamCase.getExaminerPhone());
325  }
326  if ("".equals(eamCase.getNotes())) {
327  preparedStatement.setNull(9, Types.INTEGER);
328  } else {
329  preparedStatement.setString(9, eamCase.getNotes());
330  }
331 
332  preparedStatement.executeUpdate();
333  //update the case in the caches
334  resultSet = preparedStatement.getGeneratedKeys();
335  if (!resultSet.next()) {
336  throw new CentralRepoException(String.format("Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
337  }
338  int caseID = resultSet.getInt(1); //last_insert_rowid()
339  CorrelationCase correlationCase = new CorrelationCase(caseID, eamCase.getCaseUUID(), eamCase.getOrg(),
340  eamCase.getDisplayName(), eamCase.getCreationDate(), eamCase.getCaseNumber(), eamCase.getExaminerName(),
341  eamCase.getExaminerEmail(), eamCase.getExaminerPhone(), eamCase.getNotes());
342  caseCacheByUUID.put(eamCase.getCaseUUID(), correlationCase);
343  caseCacheById.put(caseID, correlationCase);
344  } catch (SQLException ex) {
345  throw new CentralRepoException("Error inserting new case.", ex); // NON-NLS
346  } finally {
347  CentralRepoDbUtil.closeResultSet(resultSet);
348  CentralRepoDbUtil.closeStatement(preparedStatement);
349  CentralRepoDbUtil.closeConnection(conn);
350  }
351 
352  // get a new version with the updated ID
353  return getCaseByUUID(eamCase.getCaseUUID());
354  }
355 
361  @Override
362  public CorrelationCase newCase(Case autopsyCase) throws CentralRepoException {
363  if (autopsyCase == null) {
364  throw new CentralRepoException("Case is null");
365  }
366 
367  CorrelationCase curCeCase = new CorrelationCase(
368  -1,
369  autopsyCase.getName(), // unique case ID
370  CentralRepoOrganization.getDefault(),
371  autopsyCase.getDisplayName(),
372  autopsyCase.getCreatedDate(),
373  autopsyCase.getNumber(),
374  autopsyCase.getExaminer(),
375  autopsyCase.getExaminerEmail(),
376  autopsyCase.getExaminerPhone(),
377  autopsyCase.getCaseNotes());
378  return newCase(curCeCase);
379  }
380 
381  @Override
382  public CorrelationCase getCase(Case autopsyCase) throws CentralRepoException {
383  return getCaseByUUID(autopsyCase.getName());
384  }
385 
391  @Override
392  public void updateCase(CorrelationCase eamCase) throws CentralRepoException {
393  if (eamCase == null) {
394  throw new CentralRepoException("Correlation case is null");
395  }
396 
397  Connection conn = connect();
398 
399  PreparedStatement preparedStatement = null;
400  String sql = "UPDATE cases "
401  + "SET org_id=?, case_name=?, creation_date=?, case_number=?, examiner_name=?, examiner_email=?, examiner_phone=?, notes=? "
402  + "WHERE case_uid=?";
403 
404  try {
405  preparedStatement = conn.prepareStatement(sql);
406 
407  if (null == eamCase.getOrg()) {
408  preparedStatement.setNull(1, Types.INTEGER);
409  } else {
410  preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
411  }
412  preparedStatement.setString(2, eamCase.getDisplayName());
413  preparedStatement.setString(3, eamCase.getCreationDate());
414 
415  if ("".equals(eamCase.getCaseNumber())) {
416  preparedStatement.setNull(4, Types.INTEGER);
417  } else {
418  preparedStatement.setString(4, eamCase.getCaseNumber());
419  }
420  if ("".equals(eamCase.getExaminerName())) {
421  preparedStatement.setNull(5, Types.INTEGER);
422  } else {
423  preparedStatement.setString(5, eamCase.getExaminerName());
424  }
425  if ("".equals(eamCase.getExaminerEmail())) {
426  preparedStatement.setNull(6, Types.INTEGER);
427  } else {
428  preparedStatement.setString(6, eamCase.getExaminerEmail());
429  }
430  if ("".equals(eamCase.getExaminerPhone())) {
431  preparedStatement.setNull(7, Types.INTEGER);
432  } else {
433  preparedStatement.setString(7, eamCase.getExaminerPhone());
434  }
435  if ("".equals(eamCase.getNotes())) {
436  preparedStatement.setNull(8, Types.INTEGER);
437  } else {
438  preparedStatement.setString(8, eamCase.getNotes());
439  }
440 
441  preparedStatement.setString(9, eamCase.getCaseUUID());
442 
443  preparedStatement.executeUpdate();
444  //update the case in the cache
445  caseCacheById.put(eamCase.getID(), eamCase);
446  caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
447  } catch (SQLException ex) {
448  throw new CentralRepoException("Error updating case.", ex); // NON-NLS
449  } finally {
450  CentralRepoDbUtil.closeStatement(preparedStatement);
451  CentralRepoDbUtil.closeConnection(conn);
452  }
453  }
454 
462  @Override
463  public CorrelationCase getCaseByUUID(String caseUUID) throws CentralRepoException {
464  try {
465  return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
466  } catch (CacheLoader.InvalidCacheLoadException ignored) {
467  //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
468  return null;
469  } catch (ExecutionException ex) {
470  throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
471  }
472  }
473 
481  private CorrelationCase getCaseByUUIDFromCr(String caseUUID) throws CentralRepoException {
482  Connection conn = connect();
483 
484  CorrelationCase eamCaseResult = null;
485  PreparedStatement preparedStatement = null;
486  ResultSet resultSet = null;
487 
488  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
489  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
490  + "FROM cases "
491  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
492  + "WHERE case_uid=?";
493 
494  try {
495  preparedStatement = conn.prepareStatement(sql);
496  preparedStatement.setString(1, caseUUID);
497  resultSet = preparedStatement.executeQuery();
498  if (resultSet.next()) {
499  eamCaseResult = getEamCaseFromResultSet(resultSet);
500  }
501  if (eamCaseResult != null) {
502  //Update the version in the other cache
503  caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
504  }
505  } catch (SQLException ex) {
506  throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
507  } finally {
508  CentralRepoDbUtil.closeResultSet(resultSet);
509  CentralRepoDbUtil.closeStatement(preparedStatement);
510  CentralRepoDbUtil.closeConnection(conn);
511  }
512 
513  return eamCaseResult;
514  }
515 
523  @Override
524  public CorrelationCase getCaseById(int caseId) throws CentralRepoException {
525  try {
526  return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
527  } catch (CacheLoader.InvalidCacheLoadException ignored) {
528  //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
529  return null;
530  } catch (ExecutionException ex) {
531  throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
532  }
533  }
534 
542  private CorrelationCase getCaseByIdFromCr(int caseId) throws CentralRepoException {
543  Connection conn = connect();
544 
545  CorrelationCase eamCaseResult = null;
546  PreparedStatement preparedStatement = null;
547  ResultSet resultSet = null;
548 
549  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
550  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
551  + "FROM cases "
552  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
553  + "WHERE cases.id=?";
554  try {
555  preparedStatement = conn.prepareStatement(sql);
556  preparedStatement.setInt(1, caseId);
557  resultSet = preparedStatement.executeQuery();
558  if (resultSet.next()) {
559  eamCaseResult = getEamCaseFromResultSet(resultSet);
560  }
561  if (eamCaseResult != null) {
562  //Update the version in the other cache
563  caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
564  }
565  } catch (SQLException ex) {
566  throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
567  } finally {
568  CentralRepoDbUtil.closeResultSet(resultSet);
569  CentralRepoDbUtil.closeStatement(preparedStatement);
570  CentralRepoDbUtil.closeConnection(conn);
571  }
572 
573  return eamCaseResult;
574  }
575 
581  @Override
582  public List<CorrelationCase> getCases() throws CentralRepoException {
583  Connection conn = connect();
584 
585  List<CorrelationCase> cases = new ArrayList<>();
586  CorrelationCase eamCaseResult;
587  PreparedStatement preparedStatement = null;
588  ResultSet resultSet = null;
589 
590  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
591  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
592  + "FROM cases "
593  + "LEFT JOIN organizations ON cases.org_id=organizations.id";
594 
595  try {
596  preparedStatement = conn.prepareStatement(sql);
597  resultSet = preparedStatement.executeQuery();
598  while (resultSet.next()) {
599  eamCaseResult = getEamCaseFromResultSet(resultSet);
600  cases.add(eamCaseResult);
601  }
602  } catch (SQLException ex) {
603  throw new CentralRepoException("Error getting all cases.", ex); // NON-NLS
604  } finally {
605  CentralRepoDbUtil.closeResultSet(resultSet);
606  CentralRepoDbUtil.closeStatement(preparedStatement);
607  CentralRepoDbUtil.closeConnection(conn);
608  }
609 
610  return cases;
611  }
612 
623  private static String getDataSourceByDSObjectIdCacheKey(int caseId, Long dataSourceObjectId) {
624  return "Case" + caseId + "DsObjectId" + dataSourceObjectId; //NON-NLS
625  }
626 
636  private static String getDataSourceByIdCacheKey(int caseId, int dataSourceId) {
637  return "Case" + caseId + "Id" + dataSourceId; //NON-NLS
638  }
639 
645  @Override
646  public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws CentralRepoException {
647  if (eamDataSource.getCaseID() == -1) {
648  throw new CentralRepoException("Case ID is -1");
649  }
650  if (eamDataSource.getDeviceID() == null) {
651  throw new CentralRepoException("Device ID is null");
652  }
653  if (eamDataSource.getName() == null) {
654  throw new CentralRepoException("Name is null");
655  }
656  if (eamDataSource.getID() != -1) {
657  // This data source is already in the central repo
658  return eamDataSource;
659  }
660 
661  Connection conn = connect();
662 
663  PreparedStatement preparedStatement = null;
664  //The conflict clause exists in case multiple nodes are trying to add the data source because it did not exist at the same time
665  String sql = "INSERT INTO data_sources(device_id, case_id, name, datasource_obj_id, md5, sha1, sha256) VALUES (?, ?, ?, ?, ?, ?, ?) "
666  + getConflictClause();
667  ResultSet resultSet = null;
668  try {
669  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
670 
671  preparedStatement.setString(1, eamDataSource.getDeviceID());
672  preparedStatement.setInt(2, eamDataSource.getCaseID());
673  preparedStatement.setString(3, eamDataSource.getName());
674  preparedStatement.setLong(4, eamDataSource.getDataSourceObjectID());
675  preparedStatement.setString(5, eamDataSource.getMd5());
676  preparedStatement.setString(6, eamDataSource.getSha1());
677  preparedStatement.setString(7, eamDataSource.getSha256());
678 
679  preparedStatement.executeUpdate();
680  resultSet = preparedStatement.getGeneratedKeys();
681  if (!resultSet.next()) {
682  /*
683  * If nothing was inserted, then return the data source that
684  * exists in the Central Repository.
685  *
686  * This is expected to occur with PostgreSQL Central Repository
687  * databases.
688  */
689  try {
690  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
691  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
692  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
693  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
694  throw new CentralRepoException(String.format("Unable to to INSERT or get data source %s in central repo:", eamDataSource.getName()), getException);
695  }
696  } else {
697  //if a new data source was added to the central repository update the caches to include it and return it
698  int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
699  CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName(), eamDataSource.getDataSourceObjectID(), eamDataSource.getMd5(), eamDataSource.getSha1(), eamDataSource.getSha256());
700  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(dataSource.getCaseID(), dataSource.getDataSourceObjectID()), dataSource);
701  dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
702  return dataSource;
703  }
704 
705  } catch (SQLException insertException) {
706  /*
707  * If an exception was thrown causing us to not return a new data
708  * source, attempt to get an existing data source with the same case
709  * ID and data source object ID.
710  *
711  * This exception block is expected to occur with SQLite Central
712  * Repository databases.
713  */
714  try {
715  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
716  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
717  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
718  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
719  throw new CentralRepoException(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);
720  }
721  } finally {
722  CentralRepoDbUtil.closeResultSet(resultSet);
723  CentralRepoDbUtil.closeStatement(preparedStatement);
724  CentralRepoDbUtil.closeConnection(conn);
725  }
726  }
727 
739  @Override
740  public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) throws CentralRepoException {
741 
742  if (correlationCase == null) {
743  throw new CentralRepoException("Correlation case is null");
744  }
745  try {
746  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase.getID(), dataSourceObjectId));
747  } catch (CacheLoader.InvalidCacheLoadException ignored) {
748  //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
749  return null;
750  } catch (ExecutionException ex) {
751  throw new CentralRepoException("Error getting data source from central repository", ex);
752  }
753  }
754 
767  private CorrelationDataSource getDataSourceFromCr(int correlationCaseId, Long dataSourceObjectId) throws CentralRepoException {
768  Connection conn = connect();
769 
770  CorrelationDataSource eamDataSourceResult = null;
771  PreparedStatement preparedStatement = null;
772  ResultSet resultSet = null;
773 
774  String sql = "SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; // NON-NLS
775 
776  try {
777  preparedStatement = conn.prepareStatement(sql);
778  preparedStatement.setLong(1, dataSourceObjectId);
779  preparedStatement.setInt(2, correlationCaseId);
780  resultSet = preparedStatement.executeQuery();
781  if (resultSet.next()) {
782  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
783  }
784  if (eamDataSourceResult != null) {
785  dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCaseId, eamDataSourceResult.getID()), eamDataSourceResult);
786  }
787  } catch (SQLException ex) {
788  throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
789  } finally {
790  CentralRepoDbUtil.closeResultSet(resultSet);
791  CentralRepoDbUtil.closeStatement(preparedStatement);
792  CentralRepoDbUtil.closeConnection(conn);
793  }
794 
795  return eamDataSourceResult;
796  }
797 
807  @Override
808  public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
809  if (correlationCase == null) {
810  throw new CentralRepoException("Correlation case is null");
811  }
812  try {
813  return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
814  } catch (CacheLoader.InvalidCacheLoadException ignored) {
815  //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
816  return null;
817  } catch (ExecutionException ex) {
818  throw new CentralRepoException("Error getting data source from central repository", ex);
819  }
820  }
821 
831  private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
832  Connection conn = connect();
833 
834  CorrelationDataSource eamDataSourceResult = null;
835  PreparedStatement preparedStatement = null;
836  ResultSet resultSet = null;
837 
838  String sql = "SELECT * FROM data_sources WHERE id=? AND case_id=?"; // NON-NLS
839 
840  try {
841  preparedStatement = conn.prepareStatement(sql);
842  preparedStatement.setInt(1, dataSourceId);
843  preparedStatement.setInt(2, correlationCase.getID());
844  resultSet = preparedStatement.executeQuery();
845  if (resultSet.next()) {
846  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
847  }
848  if (eamDataSourceResult != null) {
849  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
850  }
851  } catch (SQLException ex) {
852  throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
853  } finally {
854  CentralRepoDbUtil.closeResultSet(resultSet);
855  CentralRepoDbUtil.closeStatement(preparedStatement);
856  CentralRepoDbUtil.closeConnection(conn);
857  }
858 
859  return eamDataSourceResult;
860  }
861 
867  @Override
868  public List<CorrelationDataSource> getDataSources() throws CentralRepoException {
869  Connection conn = connect();
870 
871  List<CorrelationDataSource> dataSources = new ArrayList<>();
872  CorrelationDataSource eamDataSourceResult;
873  PreparedStatement preparedStatement = null;
874  ResultSet resultSet = null;
875 
876  String sql = "SELECT * FROM data_sources";
877 
878  try {
879  preparedStatement = conn.prepareStatement(sql);
880  resultSet = preparedStatement.executeQuery();
881  while (resultSet.next()) {
882  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
883  dataSources.add(eamDataSourceResult);
884  }
885  } catch (SQLException ex) {
886  throw new CentralRepoException("Error getting all data sources.", ex); // NON-NLS
887  } finally {
888  CentralRepoDbUtil.closeResultSet(resultSet);
889  CentralRepoDbUtil.closeStatement(preparedStatement);
890  CentralRepoDbUtil.closeConnection(conn);
891  }
892 
893  return dataSources;
894  }
895 
901  @Override
902  public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
903  updateDataSourceStringValue(eamDataSource, "md5", eamDataSource.getMd5());
904  }
905 
911  @Override
912  public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
913  updateDataSourceStringValue(eamDataSource, "sha1", eamDataSource.getSha1());
914  }
915 
922  @Override
923  public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
924  updateDataSourceStringValue(eamDataSource, "sha256", eamDataSource.getSha256());
925  }
926 
934  private void updateDataSourceStringValue(CorrelationDataSource eamDataSource, String column, String value) throws CentralRepoException {
935  if (eamDataSource == null) {
936  throw new CentralRepoException("Correlation data source is null");
937  }
938 
939  Connection conn = connect();
940 
941  PreparedStatement preparedStatement = null;
942  String sql = "UPDATE data_sources "
943  + "SET " + column + "=? "
944  + "WHERE id=?";
945 
946  try {
947  preparedStatement = conn.prepareStatement(sql);
948 
949  preparedStatement.setString(1, value);
950  preparedStatement.setInt(2, eamDataSource.getID());
951 
952  preparedStatement.executeUpdate();
953  //update the case in the cache
954  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()), eamDataSource);
955  dataSourceCacheById.put(getDataSourceByIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getID()), eamDataSource);
956  } catch (SQLException ex) {
957  throw new CentralRepoException(String.format("Error updating data source (obj_id=%d).", eamDataSource.getDataSourceObjectID()), ex); // NON-NLS
958  } finally {
959  CentralRepoDbUtil.closeStatement(preparedStatement);
960  CentralRepoDbUtil.closeConnection(conn);
961  }
962  }
963 
972  @Override
973  public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws CentralRepoException {
974 
975  Connection conn = connect();
976 
977  PreparedStatement preparedStatement = null;
978 
979  String sql = "UPDATE data_sources SET name = ? WHERE id = ?";
980 
981  try {
982  preparedStatement = conn.prepareStatement(sql);
983  preparedStatement.setString(1, newName);
984  preparedStatement.setInt(2, eamDataSource.getID());
985  preparedStatement.executeUpdate();
986 
987  CorrelationDataSource updatedDataSource = new CorrelationDataSource(
988  eamDataSource.getCaseID(),
989  eamDataSource.getID(),
990  eamDataSource.getDeviceID(),
991  newName,
992  eamDataSource.getDataSourceObjectID(),
993  eamDataSource.getMd5(),
994  eamDataSource.getSha1(),
995  eamDataSource.getSha256());
996 
997  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getDataSourceObjectID()), updatedDataSource);
998  dataSourceCacheById.put(getDataSourceByIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getID()), updatedDataSource);
999  } catch (SQLException ex) {
1000  throw new CentralRepoException("Error updating name of data source with ID " + eamDataSource.getDataSourceObjectID()
1001  + " to " + newName, ex); // NON-NLS
1002  } finally {
1003  CentralRepoDbUtil.closeStatement(preparedStatement);
1004  CentralRepoDbUtil.closeConnection(conn);
1005  }
1006  }
1007 
1014  @Override
1015  public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1016  checkAddArtifactInstanceNulls(eamArtifact);
1017 
1018  // @@@ We should cache the case and data source IDs in memory
1019  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1020  boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
1021 
1022  String sql;
1023  // _instance table for accounts have an additional account_id column
1024  if (artifactHasAnAccount) {
1025  sql = "INSERT INTO "
1026  + tableName
1027  + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
1028  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
1029  + getConflictClause();
1030  } else {
1031  sql = "INSERT INTO "
1032  + tableName
1033  + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1034  + "VALUES (?, ?, ?, ?, ?, ?, ?) "
1035  + getConflictClause();
1036  }
1037 
1038  try (Connection conn = connect();
1039  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1040 
1041  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1042  preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
1043  preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1044  preparedStatement.setString(3, eamArtifact.getCorrelationValue());
1045  preparedStatement.setString(4, eamArtifact.getFilePath().toLowerCase());
1046  preparedStatement.setByte(5, eamArtifact.getKnownStatus().getFileKnownValue());
1047 
1048  if ("".equals(eamArtifact.getComment())) {
1049  preparedStatement.setNull(6, Types.INTEGER);
1050  } else {
1051  preparedStatement.setString(6, eamArtifact.getComment());
1052  }
1053  preparedStatement.setLong(7, eamArtifact.getFileObjectId());
1054 
1055  // set in the accountId only for artifacts that represent accounts
1056  if (artifactHasAnAccount) {
1057  if (eamArtifact.getAccountId() >= 0) {
1058  preparedStatement.setLong(8, eamArtifact.getAccountId());
1059  } else {
1060  preparedStatement.setNull(8, Types.INTEGER);
1061  }
1062  }
1063 
1064  preparedStatement.executeUpdate();
1065  }
1066 
1067  } catch (SQLException ex) {
1068  throw new CentralRepoException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
1069  }
1070  }
1071 
1084  @Override
1085  public CentralRepoAccount getOrCreateAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1086  // Get the account fom the accounts table
1087  String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1088 
1089  // insert the account. If there is a conflict, ignore it.
1090  String insertSQL;
1091  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
1092  case POSTGRESQL:
1093  insertSQL = "INSERT INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) " + getConflictClause(); //NON-NLS
1094  break;
1095  case SQLITE:
1096  insertSQL = "INSERT OR IGNORE INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) "; //NON-NLS
1097  break;
1098  default:
1099  throw new CentralRepoException(String.format("Cannot add account to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
1100  }
1101 
1102  try (Connection connection = connect();
1103  PreparedStatement preparedStatement = connection.prepareStatement(insertSQL);) {
1104 
1105  preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1106  preparedStatement.setString(2, normalizedAccountID);
1107 
1108  preparedStatement.executeUpdate();
1109 
1110  // get the account from the db - should exist now.
1111  return getAccount(crAccountType, normalizedAccountID);
1112  } catch (SQLException ex) {
1113  throw new CentralRepoException("Error adding an account to CR database.", ex);
1114  }
1115  }
1116 
1117  @Override
1118  public Optional<CentralRepoAccountType> getAccountTypeByName(String accountTypeName) throws CentralRepoException {
1119  try {
1120  return accountTypesCache.get(accountTypeName, () -> getCRAccountTypeFromDb(accountTypeName));
1121  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException ex) {
1122  throw new CentralRepoException("Error looking up CR account type in cache.", ex);
1123  }
1124  }
1125 
1126  @Override
1127  public Collection<CentralRepoAccountType> getAllAccountTypes() throws CentralRepoException {
1128 
1129  Collection<CentralRepoAccountType> accountTypes = new ArrayList<>();
1130 
1131  String sql = "SELECT * FROM account_types";
1132  try (Connection conn = connect();
1133  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1134 
1135  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1136  while (resultSet.next()) {
1137  Account.Type acctType = new Account.Type(resultSet.getString("type_name"), resultSet.getString("display_name"));
1138  CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1139 
1140  accountTypes.add(crAccountType);
1141  }
1142  }
1143  } catch (SQLException ex) {
1144  throw new CentralRepoException("Error getting account types from central repository.", ex); // NON-NLS
1145  }
1146  return accountTypes;
1147  }
1148 
1158  private Optional<CentralRepoAccountType> getCRAccountTypeFromDb(String accountTypeName) throws CentralRepoException {
1159 
1160  String sql = "SELECT * FROM account_types WHERE type_name = ?";
1161  try (Connection conn = connect();
1162  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1163 
1164  preparedStatement.setString(1, accountTypeName);
1165  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1166  if (resultSet.next()) {
1167  Account.Type acctType = new Account.Type(accountTypeName, resultSet.getString("display_name"));
1168  CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1169  accountTypesCache.put(accountTypeName, Optional.of(crAccountType));
1170  return Optional.of(crAccountType);
1171  } else {
1172  accountTypesCache.put(accountTypeName, Optional.empty());
1173  return Optional.empty();
1174  }
1175  }
1176  } catch (SQLException ex) {
1177  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
1178  }
1179  }
1180 
1199  @Override
1200  public CentralRepoAccount getAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1201  String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1202  CentralRepoAccount crAccount = accountsCache.getIfPresent(Pair.of(crAccountType, normalizedAccountID));
1203  if (crAccount == null) {
1204  crAccount = getCRAccountFromDb(crAccountType, normalizedAccountID);
1205  if (crAccount != null) {
1206  accountsCache.put(Pair.of(crAccountType, normalizedAccountID), crAccount);
1207  }
1208  }
1209 
1210  return crAccount;
1211  }
1212 
1225  private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
1226 
1227  CentralRepoAccount account = null;
1228 
1229  String sql = "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?";
1230  try (Connection connection = connect();
1231  PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
1232 
1233  preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1234  preparedStatement.setString(2, accountUniqueID);
1235 
1236  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1237  if (resultSet.next()) {
1238  account = new CentralRepoAccount(resultSet.getInt("id"), crAccountType, resultSet.getString("account_unique_identifier")); //NON-NLS
1239  }
1240  }
1241  } catch (SQLException ex) {
1242  throw new CentralRepoException("Error getting account type id", ex);
1243  }
1244 
1245  return account;
1246  }
1247 
1248  private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1249  if (eamArtifact == null) {
1250  throw new CentralRepoException("CorrelationAttribute is null");
1251  }
1252  if (eamArtifact.getCorrelationType() == null) {
1253  throw new CentralRepoException("Correlation type is null");
1254  }
1255  if (eamArtifact.getCorrelationValue() == null) {
1256  throw new CentralRepoException("Correlation value is null");
1257  }
1258  if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
1259  throw new CentralRepoException("Artifact value too long for central repository."
1260  + "\nCorrelationArtifact ID: " + eamArtifact.getID()
1261  + "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1262  + "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1263 
1264  }
1265  if (eamArtifact.getCorrelationCase() == null) {
1266  throw new CentralRepoException("CorrelationAttributeInstance case is null");
1267  }
1268  if (eamArtifact.getCorrelationDataSource() == null) {
1269  throw new CentralRepoException("CorrelationAttributeInstance data source is null");
1270  }
1271  if (eamArtifact.getKnownStatus() == null) {
1272  throw new CentralRepoException("CorrelationAttributeInstance known status is null");
1273  }
1274  }
1275 
1276  @Override
1277  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1278  if (value == null) {
1279  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null value");
1280  }
1281  return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
1282  }
1283 
1284  @Override
1285  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) throws CentralRepoException, CorrelationAttributeNormalizationException {
1286  if (aType == null) {
1287  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1288  }
1289  if (values == null || values.isEmpty()) {
1290  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1291  }
1292  return getArtifactInstances(prepareGetInstancesSql(aType, values), aType);
1293  }
1294 
1295  @Override
1296  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) throws CentralRepoException, CorrelationAttributeNormalizationException {
1297  if (aType == null) {
1298  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1299  }
1300  if (values == null || values.isEmpty()) {
1301  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1302  }
1303  if (caseIds == null || caseIds.isEmpty()) {
1304  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified cases");
1305  }
1306  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1307  String sql
1308  = " and "
1309  + tableName
1310  + ".case_id in ('";
1311  StringBuilder inValuesBuilder = new StringBuilder(prepareGetInstancesSql(aType, values));
1312  inValuesBuilder.append(sql);
1313  inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '")));
1314  inValuesBuilder.append("')");
1315  return getArtifactInstances(inValuesBuilder.toString(), aType);
1316  }
1317 
1330  private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) throws CorrelationAttributeNormalizationException {
1331  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1332  String sql
1333  = "SELECT "
1334  + tableName
1335  + ".id as instance_id,"
1336  + tableName
1337  + ".value,"
1338  + tableName
1339  + ".file_obj_id,"
1340  + " 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 "
1341  + tableName
1342  + " LEFT JOIN cases ON "
1343  + tableName
1344  + ".case_id=cases.id"
1345  + " LEFT JOIN organizations ON cases.org_id=organizations.id"
1346  + " LEFT JOIN data_sources ON "
1347  + tableName
1348  + ".data_source_id=data_sources.id"
1349  + " WHERE value IN (";
1350  StringBuilder inValuesBuilder = new StringBuilder(sql);
1351  for (String value : values) {
1352  if (value != null) {
1353  inValuesBuilder.append("'");
1354  inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1355  inValuesBuilder.append("',");
1356  }
1357  }
1358  inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1359  inValuesBuilder.append(")");
1360  return inValuesBuilder.toString();
1361  }
1362 
1377  private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, CentralRepoException {
1378  Connection conn = connect();
1379  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1380  CorrelationAttributeInstance artifactInstance;
1381  PreparedStatement preparedStatement = null;
1382  ResultSet resultSet = null;
1383  try {
1384  preparedStatement = conn.prepareStatement(sql);
1385  resultSet = preparedStatement.executeQuery();
1386  while (resultSet.next()) {
1387  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1388  artifactInstances.add(artifactInstance);
1389  }
1390  } catch (SQLException ex) {
1391  throw new CentralRepoException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1392  } finally {
1393  CentralRepoDbUtil.closeResultSet(resultSet);
1394  CentralRepoDbUtil.closeStatement(preparedStatement);
1395  CentralRepoDbUtil.closeConnection(conn);
1396  }
1397  return artifactInstances;
1398  }
1399 
1410  @Override
1411  public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1412  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1413 
1414  Connection conn = connect();
1415 
1416  Long instanceCount = 0L;
1417  PreparedStatement preparedStatement = null;
1418  ResultSet resultSet = null;
1419 
1420  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1421  String sql
1422  = "SELECT count(*) FROM "
1423  + tableName
1424  + " WHERE value=?";
1425 
1426  try {
1427  preparedStatement = conn.prepareStatement(sql);
1428  preparedStatement.setString(1, normalizedValue);
1429  resultSet = preparedStatement.executeQuery();
1430  resultSet.next();
1431  instanceCount = resultSet.getLong(1);
1432  } catch (SQLException ex) {
1433  throw new CentralRepoException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1434  } finally {
1435  CentralRepoDbUtil.closeResultSet(resultSet);
1436  CentralRepoDbUtil.closeStatement(preparedStatement);
1437  CentralRepoDbUtil.closeConnection(conn);
1438  }
1439 
1440  return instanceCount;
1441  }
1442 
1443  @Override
1444  public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws CentralRepoException, CorrelationAttributeNormalizationException {
1445  if (corAttr == null) {
1446  throw new CentralRepoException("CorrelationAttribute is null");
1447  }
1448  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1449  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1450  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1451  return commonalityPercentage.intValue();
1452  }
1453 
1464  @Override
1465  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1466  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1467 
1468  Connection conn = connect();
1469 
1470  Long instanceCount = 0L;
1471  PreparedStatement preparedStatement = null;
1472  ResultSet resultSet = null;
1473 
1474  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1475  String sql
1476  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1477  + tableName
1478  + " WHERE value=?) AS "
1479  + tableName
1480  + "_distinct_case_data_source_tuple";
1481 
1482  try {
1483  preparedStatement = conn.prepareStatement(sql);
1484  preparedStatement.setString(1, normalizedValue);
1485  resultSet = preparedStatement.executeQuery();
1486  resultSet.next();
1487  instanceCount = resultSet.getLong(1);
1488  } catch (SQLException ex) {
1489  throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1490  } finally {
1491  CentralRepoDbUtil.closeResultSet(resultSet);
1492  CentralRepoDbUtil.closeStatement(preparedStatement);
1493  CentralRepoDbUtil.closeConnection(conn);
1494  }
1495 
1496  return instanceCount;
1497  }
1498 
1499  @Override
1500  public Long getCountCasesWithOtherInstances(CorrelationAttributeInstance instance) throws CentralRepoException, CorrelationAttributeNormalizationException {
1501  Long instanceCount = 0L;
1502  if (instance != null) {
1503  Long sourceObjID = instance.getFileObjectId();
1504  //The CorrelationAttributeInstance will have a CorrelationCase, however that correlation case's ID will be null if the case is not in the CR.
1505  int correlationCaseId = instance.getCorrelationCase().getID();
1506  String normalizedValue = CorrelationAttributeNormalizer.normalize(instance.getCorrelationType(), instance.getCorrelationValue());
1507  Connection conn = connect();
1508  PreparedStatement preparedStatement = null;
1509  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(instance.getCorrelationType());
1510  ResultSet resultSet = null;
1511  try {
1512  if (correlationCaseId > 0 && sourceObjID != null) {
1513  //The CorrelationCase is in the Central repository.
1514  String sql
1515  = "SELECT count(*) FROM (SELECT DISTINCT case_id FROM " //Get distinct cases with a matching value in the corresponding table from the central repository.
1516  + tableName
1517  + " WHERE value=? AND NOT (file_obj_id=? AND case_id=?)) AS " //Check the file_obj_id AND case_id to ensure we ignore the currently selected instance.
1518  + tableName
1519  + "_other_case_count";
1520  preparedStatement = conn.prepareStatement(sql);
1521  preparedStatement.setString(1, normalizedValue);
1522  preparedStatement.setLong(2, sourceObjID);
1523  preparedStatement.setInt(3, correlationCaseId);
1524  } else {
1525  //The CorrelationCase is NOT in the central repository.
1526  String sql
1527  = "SELECT count(*) FROM (SELECT DISTINCT case_id FROM " //Get all distinct cases with a matching value in the corresponding table from the central repository.
1528  + tableName
1529  + " WHERE value=? AS "
1530  + tableName
1531  + "_other_case_count";
1532  preparedStatement = conn.prepareStatement(sql);
1533  preparedStatement.setString(1, normalizedValue);
1534  }
1535  resultSet = preparedStatement.executeQuery();
1536  resultSet.next();
1537  instanceCount = resultSet.getLong(1);
1538  } catch (SQLException ex) {
1539  throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1540  } finally {
1541  CentralRepoDbUtil.closeResultSet(resultSet);
1542  CentralRepoDbUtil.closeStatement(preparedStatement);
1543  CentralRepoDbUtil.closeConnection(conn);
1544  }
1545  }
1546 
1547  return instanceCount;
1548  }
1549 
1550  @Override
1551  public Long getCountUniqueDataSources() throws CentralRepoException {
1552  Connection conn = connect();
1553 
1554  Long instanceCount = 0L;
1555  PreparedStatement preparedStatement = null;
1556  ResultSet resultSet = null;
1557 
1558  String stmt = "SELECT count(*) FROM data_sources";
1559 
1560  try {
1561  preparedStatement = conn.prepareStatement(stmt);
1562  resultSet = preparedStatement.executeQuery();
1563  resultSet.next();
1564  instanceCount = resultSet.getLong(1);
1565  } catch (SQLException ex) {
1566  throw new CentralRepoException("Error counting data sources.", ex); // NON-NLS
1567  } finally {
1568  CentralRepoDbUtil.closeResultSet(resultSet);
1569  CentralRepoDbUtil.closeStatement(preparedStatement);
1570  CentralRepoDbUtil.closeConnection(conn);
1571  }
1572 
1573  return instanceCount;
1574  }
1575 
1587  @Override
1588  public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws CentralRepoException {
1589  Connection conn = connect();
1590 
1591  Long instanceCount = 0L;
1592  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1593  PreparedStatement preparedStatement = null;
1594  ResultSet resultSet = null;
1595 
1596  //Create query to get count of all instances in the database for the specified case specific data source
1597  String sql = "SELECT 0 ";
1598 
1599  for (CorrelationAttributeInstance.Type type : artifactTypes) {
1600  String table_name = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1601  sql
1602  += "+ (SELECT count(*) FROM "
1603  + table_name
1604  + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1605  }
1606  try {
1607  preparedStatement = conn.prepareStatement(sql);
1608 
1609  resultSet = preparedStatement.executeQuery();
1610  resultSet.next();
1611  instanceCount = resultSet.getLong(1);
1612  } catch (SQLException ex) {
1613  throw new CentralRepoException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1614  } finally {
1615  CentralRepoDbUtil.closeResultSet(resultSet);
1616  CentralRepoDbUtil.closeStatement(preparedStatement);
1617  CentralRepoDbUtil.closeConnection(conn);
1618  }
1619 
1620  return instanceCount;
1621  }
1622 
1630  @Override
1631  public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1632 
1633  if (eamArtifact.getCorrelationType() == null) {
1634  throw new CentralRepoException("Correlation type is null");
1635  }
1636 
1637  synchronized (bulkArtifacts) {
1638  if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
1639  bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
1640  }
1641  bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1642  bulkArtifactsCount++;
1643 
1644  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1645  commitAttributeInstancesBulk();
1646  }
1647  }
1648  }
1649 
1655  protected abstract String getConflictClause();
1656 
1661  @Override
1662  public void commitAttributeInstancesBulk() throws CentralRepoException {
1663  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1664 
1665  Connection conn = connect();
1666  PreparedStatement bulkPs = null;
1667 
1668  try {
1669  synchronized (bulkArtifacts) {
1670  if (bulkArtifactsCount == 0) {
1671  return;
1672  }
1673 
1674  for (String tableName : bulkArtifacts.keySet()) {
1675 
1676  String sql
1677  = "INSERT INTO "
1678  + tableName
1679  + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1680  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1681  + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1682  + getConflictClause();
1683 
1684  bulkPs = conn.prepareStatement(sql);
1685 
1686  Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1687  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1688 
1689  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1690 
1691  if (eamArtifact.getCorrelationCase() == null) {
1692  throw new CentralRepoException("CorrelationAttributeInstance case is null for: "
1693  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1694  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1695  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1696  }
1697  if (eamArtifact.getCorrelationDataSource() == null) {
1698  throw new CentralRepoException("CorrelationAttributeInstance data source is null for: "
1699  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1700  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1701  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1702  }
1703  if (eamArtifact.getKnownStatus() == null) {
1704  throw new CentralRepoException("CorrelationAttributeInstance known status is null for: "
1705  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1706  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1707  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1708  + "\n\tEam Instance: "
1709  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1710  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1711  }
1712 
1713  if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1714  bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1715  bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1716  bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1717  bulkPs.setString(4, eamArtifact.getCorrelationValue());
1718  bulkPs.setString(5, eamArtifact.getFilePath());
1719  bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1720  if ("".equals(eamArtifact.getComment())) {
1721  bulkPs.setNull(7, Types.INTEGER);
1722  } else {
1723  bulkPs.setString(7, eamArtifact.getComment());
1724  }
1725  bulkPs.setLong(8, eamArtifact.getFileObjectId());
1726  bulkPs.addBatch();
1727  } else {
1728  logger.log(Level.WARNING, ("Artifact value too long for central repository."
1729  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1730  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1731  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1732  + "\n\tEam Instance: "
1733  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1734  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1735  + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1736  }
1737  }
1738 
1739  }
1740 
1741  bulkPs.executeBatch();
1742  bulkArtifacts.get(tableName).clear();
1743  }
1744 
1745  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Bulk insert");
1746  HealthMonitor.submitTimingMetric(timingMetric);
1747 
1748  // Reset state
1749  bulkArtifactsCount = 0;
1750  }
1751  } catch (SQLException ex) {
1752  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
1753  } finally {
1754  CentralRepoDbUtil.closeStatement(bulkPs);
1755  CentralRepoDbUtil.closeConnection(conn);
1756  }
1757  }
1758 
1762  @Override
1763  public void bulkInsertCases(List<CorrelationCase> cases) throws CentralRepoException {
1764  if (cases == null) {
1765  throw new CentralRepoException("cases argument is null");
1766  }
1767 
1768  if (cases.isEmpty()) {
1769  return;
1770  }
1771 
1772  Connection conn = connect();
1773 
1774  int counter = 0;
1775  PreparedStatement bulkPs = null;
1776  try {
1777  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1778  + "examiner_name, examiner_email, examiner_phone, notes) "
1779  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1780  + getConflictClause();
1781  bulkPs = conn.prepareStatement(sql);
1782 
1783  for (CorrelationCase eamCase : cases) {
1784  bulkPs.setString(1, eamCase.getCaseUUID());
1785  if (null == eamCase.getOrg()) {
1786  bulkPs.setNull(2, Types.INTEGER);
1787  } else {
1788  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1789  }
1790  bulkPs.setString(3, eamCase.getDisplayName());
1791  bulkPs.setString(4, eamCase.getCreationDate());
1792 
1793  if ("".equals(eamCase.getCaseNumber())) {
1794  bulkPs.setNull(5, Types.INTEGER);
1795  } else {
1796  bulkPs.setString(5, eamCase.getCaseNumber());
1797  }
1798  if ("".equals(eamCase.getExaminerName())) {
1799  bulkPs.setNull(6, Types.INTEGER);
1800  } else {
1801  bulkPs.setString(6, eamCase.getExaminerName());
1802  }
1803  if ("".equals(eamCase.getExaminerEmail())) {
1804  bulkPs.setNull(7, Types.INTEGER);
1805  } else {
1806  bulkPs.setString(7, eamCase.getExaminerEmail());
1807  }
1808  if ("".equals(eamCase.getExaminerPhone())) {
1809  bulkPs.setNull(8, Types.INTEGER);
1810  } else {
1811  bulkPs.setString(8, eamCase.getExaminerPhone());
1812  }
1813  if ("".equals(eamCase.getNotes())) {
1814  bulkPs.setNull(9, Types.INTEGER);
1815  } else {
1816  bulkPs.setString(9, eamCase.getNotes());
1817  }
1818 
1819  bulkPs.addBatch();
1820 
1821  counter++;
1822 
1823  // limit a batch's max size to bulkArtifactsThreshold
1824  if (counter >= bulkArtifactsThreshold) {
1825  bulkPs.executeBatch();
1826  counter = 0;
1827  }
1828  }
1829  // send the remaining batch records
1830  bulkPs.executeBatch();
1831  } catch (SQLException ex) {
1832  throw new CentralRepoException("Error inserting bulk cases.", ex); // NON-NLS
1833  } finally {
1834  CentralRepoDbUtil.closeStatement(bulkPs);
1835  CentralRepoDbUtil.closeConnection(conn);
1836  }
1837  }
1838 
1848  @Override
1849  public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1850 
1851  if (eamArtifact == null) {
1852  throw new CentralRepoException("CorrelationAttributeInstance is null");
1853  }
1854  if (eamArtifact.getCorrelationCase() == null) {
1855  throw new CentralRepoException("Correlation case is null");
1856  }
1857  if (eamArtifact.getCorrelationDataSource() == null) {
1858  throw new CentralRepoException("Correlation data source is null");
1859  }
1860  Connection conn = connect();
1861  PreparedStatement preparedQuery = null;
1862  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1863  String sqlUpdate
1864  = "UPDATE "
1865  + tableName
1866  + " SET comment=? "
1867  + "WHERE case_id=? "
1868  + "AND data_source_id=? "
1869  + "AND value=? "
1870  + "AND file_path=?";
1871 
1872  try {
1873  preparedQuery = conn.prepareStatement(sqlUpdate);
1874  preparedQuery.setString(1, eamArtifact.getComment());
1875  preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1876  preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1877  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1878  preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1879  preparedQuery.executeUpdate();
1880  } catch (SQLException ex) {
1881  throw new CentralRepoException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1882  } finally {
1883  CentralRepoDbUtil.closeStatement(preparedQuery);
1884  CentralRepoDbUtil.closeConnection(conn);
1885  }
1886  }
1887 
1902  @Override
1903  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1904  CorrelationDataSource correlationDataSource, long objectID) throws CentralRepoException, CorrelationAttributeNormalizationException {
1905 
1906  if (correlationCase == null) {
1907  throw new CentralRepoException("Correlation case is null");
1908  }
1909 
1910  Connection conn = connect();
1911 
1912  PreparedStatement preparedStatement = null;
1913  ResultSet resultSet = null;
1914  CorrelationAttributeInstance correlationAttributeInstance = null;
1915 
1916  try {
1917 
1918  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1919  String sql
1920  = "SELECT id, value, file_path, known_status, comment FROM "
1921  + tableName
1922  + " WHERE case_id=?"
1923  + " AND file_obj_id=?";
1924 
1925  preparedStatement = conn.prepareStatement(sql);
1926  preparedStatement.setInt(1, correlationCase.getID());
1927  preparedStatement.setInt(2, (int) objectID);
1928  resultSet = preparedStatement.executeQuery();
1929  if (resultSet.next()) {
1930  int instanceId = resultSet.getInt(1);
1931  String value = resultSet.getString(2);
1932  String filePath = resultSet.getString(3);
1933  int knownStatus = resultSet.getInt(4);
1934  String comment = resultSet.getString(5);
1935 
1936  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1937  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1938  }
1939  } catch (SQLException ex) {
1940  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1941  } finally {
1942  CentralRepoDbUtil.closeResultSet(resultSet);
1943  CentralRepoDbUtil.closeStatement(preparedStatement);
1944  CentralRepoDbUtil.closeConnection(conn);
1945  }
1946 
1947  return correlationAttributeInstance;
1948  }
1949 
1964  @Override
1965  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1966  CorrelationDataSource correlationDataSource, String value, String filePath) throws CentralRepoException, CorrelationAttributeNormalizationException {
1967 
1968  if (correlationCase == null) {
1969  throw new CentralRepoException("Correlation case is null");
1970  }
1971  if (correlationDataSource == null) {
1972  throw new CentralRepoException("Correlation data source is null");
1973  }
1974  if (filePath == null) {
1975  throw new CentralRepoException("Correlation file path is null");
1976  }
1977 
1978  Connection conn = connect();
1979 
1980  PreparedStatement preparedStatement = null;
1981  ResultSet resultSet = null;
1982  CorrelationAttributeInstance correlationAttributeInstance = null;
1983 
1984  try {
1985  String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1986 
1987  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1988  String sql
1989  = "SELECT id, known_status, comment FROM "
1990  + tableName
1991  + " WHERE case_id=?"
1992  + " AND data_source_id=?"
1993  + " AND value=?"
1994  + " AND file_path=?";
1995 
1996  preparedStatement = conn.prepareStatement(sql);
1997  preparedStatement.setInt(1, correlationCase.getID());
1998  preparedStatement.setInt(2, correlationDataSource.getID());
1999  preparedStatement.setString(3, normalizedValue);
2000  preparedStatement.setString(4, filePath.toLowerCase());
2001  resultSet = preparedStatement.executeQuery();
2002  if (resultSet.next()) {
2003  int instanceId = resultSet.getInt(1);
2004  int knownStatus = resultSet.getInt(2);
2005  String comment = resultSet.getString(3);
2006  //null objectId used because we only fall back to using this method when objectID was not available
2007  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
2008  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
2009  }
2010  } catch (SQLException ex) {
2011  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2012  } finally {
2013  CentralRepoDbUtil.closeResultSet(resultSet);
2014  CentralRepoDbUtil.closeStatement(preparedStatement);
2015  CentralRepoDbUtil.closeConnection(conn);
2016  }
2017 
2018  return correlationAttributeInstance;
2019  }
2020 
2031  @Override
2032  public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws CentralRepoException {
2033  if (eamArtifact == null) {
2034  throw new CentralRepoException("CorrelationAttribute is null");
2035  }
2036  if (knownStatus == null) {
2037  throw new CentralRepoException("Known status is null");
2038  }
2039 
2040  if (eamArtifact.getCorrelationCase() == null) {
2041  throw new CentralRepoException("Correlation case is null");
2042  }
2043  if (eamArtifact.getCorrelationDataSource() == null) {
2044  throw new CentralRepoException("Correlation data source is null");
2045  }
2046 
2047  Connection conn = connect();
2048 
2049  PreparedStatement preparedUpdate = null;
2050  PreparedStatement preparedQuery = null;
2051  ResultSet resultSet = null;
2052 
2053  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
2054 
2055  String sqlQuery
2056  = "SELECT id FROM "
2057  + tableName
2058  + " WHERE case_id=? "
2059  + "AND data_source_id=? "
2060  + "AND value=? "
2061  + "AND file_path=?";
2062 
2063  String sqlUpdate
2064  = "UPDATE "
2065  + tableName
2066  + " SET known_status=? WHERE id=?";
2067 
2068  try {
2069  preparedQuery = conn.prepareStatement(sqlQuery);
2070  preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
2071  preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
2072  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
2073  preparedQuery.setString(4, eamArtifact.getFilePath());
2074  resultSet = preparedQuery.executeQuery();
2075  if (resultSet.next()) {
2076  int instance_id = resultSet.getInt("id");
2077  preparedUpdate = conn.prepareStatement(sqlUpdate);
2078 
2079  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
2080  preparedUpdate.setInt(2, instance_id);
2081 
2082  preparedUpdate.executeUpdate();
2083  } else {
2084  // In this case, the user is tagging something that isn't in the database,
2085  // which means the case and/or datasource may also not be in the database.
2086  // We could improve effiency by keeping a list of all datasources and cases
2087  // in the database, but we don't expect the user to be tagging large numbers
2088  // of items (that didn't have the CE ingest module run on them) at once.
2089  CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
2090  if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
2091  newDataSource(eamArtifact.getCorrelationDataSource());
2092  }
2093  eamArtifact.setKnownStatus(knownStatus);
2094  addArtifactInstance(eamArtifact);
2095  }
2096 
2097  } catch (SQLException ex) {
2098  throw new CentralRepoException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
2099  } finally {
2100  CentralRepoDbUtil.closeResultSet(resultSet);
2101  CentralRepoDbUtil.closeStatement(preparedUpdate);
2102  CentralRepoDbUtil.closeStatement(preparedQuery);
2103  CentralRepoDbUtil.closeConnection(conn);
2104  }
2105  }
2106 
2115  @Override
2116  public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2117 
2118  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2119 
2120  Connection conn = connect();
2121 
2122  Long badInstances = 0L;
2123  PreparedStatement preparedStatement = null;
2124  ResultSet resultSet = null;
2125 
2126  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2127  String sql
2128  = "SELECT count(*) FROM "
2129  + tableName
2130  + " WHERE value=? AND known_status=?";
2131 
2132  try {
2133  preparedStatement = conn.prepareStatement(sql);
2134  preparedStatement.setString(1, normalizedValue);
2135  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2136  resultSet = preparedStatement.executeQuery();
2137  resultSet.next();
2138  badInstances = resultSet.getLong(1);
2139  } catch (SQLException ex) {
2140  throw new CentralRepoException("Error getting count of notable artifact instances.", ex); // NON-NLS
2141  } finally {
2142  CentralRepoDbUtil.closeResultSet(resultSet);
2143  CentralRepoDbUtil.closeStatement(preparedStatement);
2144  CentralRepoDbUtil.closeConnection(conn);
2145  }
2146 
2147  return badInstances;
2148  }
2149 
2162  @Override
2163  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2164 
2165  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2166 
2167  Connection conn = connect();
2168 
2169  Collection<String> caseNames = new LinkedHashSet<>();
2170 
2171  PreparedStatement preparedStatement = null;
2172  ResultSet resultSet = null;
2173 
2174  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2175  String sql
2176  = "SELECT DISTINCT case_name FROM "
2177  + tableName
2178  + " INNER JOIN cases ON "
2179  + tableName
2180  + ".case_id=cases.id WHERE "
2181  + tableName
2182  + ".value=? AND "
2183  + tableName
2184  + ".known_status=?";
2185 
2186  try {
2187  preparedStatement = conn.prepareStatement(sql);
2188  preparedStatement.setString(1, normalizedValue);
2189  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2190  resultSet = preparedStatement.executeQuery();
2191  while (resultSet.next()) {
2192  caseNames.add(resultSet.getString("case_name"));
2193  }
2194  } catch (SQLException ex) {
2195  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2196  } finally {
2197  CentralRepoDbUtil.closeResultSet(resultSet);
2198  CentralRepoDbUtil.closeStatement(preparedStatement);
2199  CentralRepoDbUtil.closeConnection(conn);
2200  }
2201 
2202  return caseNames.stream().collect(Collectors.toList());
2203  }
2204 
2217  @Override
2218  public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2219 
2220  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2221 
2222  Connection conn = connect();
2223 
2224  Collection<String> caseNames = new LinkedHashSet<>();
2225 
2226  PreparedStatement preparedStatement = null;
2227  ResultSet resultSet = null;
2228 
2229  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2230  String sql
2231  = "SELECT DISTINCT case_name FROM "
2232  + tableName
2233  + " INNER JOIN cases ON "
2234  + tableName
2235  + ".case_id=cases.id WHERE "
2236  + tableName
2237  + ".value=? ";
2238 
2239  try {
2240  preparedStatement = conn.prepareStatement(sql);
2241  preparedStatement.setString(1, normalizedValue);
2242  resultSet = preparedStatement.executeQuery();
2243  while (resultSet.next()) {
2244  caseNames.add(resultSet.getString("case_name"));
2245  }
2246  } catch (SQLException ex) {
2247  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2248  } finally {
2249  CentralRepoDbUtil.closeResultSet(resultSet);
2250  CentralRepoDbUtil.closeStatement(preparedStatement);
2251  CentralRepoDbUtil.closeConnection(conn);
2252  }
2253 
2254  return caseNames.stream().collect(Collectors.toList());
2255  }
2256 
2264  @Override
2265  public void deleteReferenceSet(int referenceSetID) throws CentralRepoException {
2266  deleteReferenceSetEntries(referenceSetID);
2267  deleteReferenceSetEntry(referenceSetID);
2268  }
2269 
2277  private void deleteReferenceSetEntry(int referenceSetID) throws CentralRepoException {
2278  Connection conn = connect();
2279 
2280  PreparedStatement preparedStatement = null;
2281  String sql = "DELETE FROM reference_sets WHERE id=?";
2282 
2283  try {
2284  preparedStatement = conn.prepareStatement(sql);
2285  preparedStatement.setInt(1, referenceSetID);
2286  preparedStatement.executeUpdate();
2287  } catch (SQLException ex) {
2288  throw new CentralRepoException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2289  } finally {
2290  CentralRepoDbUtil.closeStatement(preparedStatement);
2291  CentralRepoDbUtil.closeConnection(conn);
2292  }
2293  }
2294 
2303  private void deleteReferenceSetEntries(int referenceSetID) throws CentralRepoException {
2304  Connection conn = connect();
2305 
2306  PreparedStatement preparedStatement = null;
2307  String sql = "DELETE FROM %s WHERE reference_set_id=?";
2308 
2309  // When other reference types are added, this will need to loop over all the tables
2310  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2311 
2312  try {
2313  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2314  preparedStatement.setInt(1, referenceSetID);
2315  preparedStatement.executeUpdate();
2316  } catch (SQLException ex) {
2317  throw new CentralRepoException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2318  } finally {
2319  CentralRepoDbUtil.closeStatement(preparedStatement);
2320  CentralRepoDbUtil.closeConnection(conn);
2321  }
2322  }
2323 
2337  @Override
2338  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws CentralRepoException {
2339  CentralRepoFileSet refSet = this.getReferenceSetByID(referenceSetID);
2340  if (refSet == null) {
2341  return false;
2342  }
2343 
2344  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2345  }
2346 
2358  @Override
2359  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2360  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2361  }
2362 
2363  @Override
2364  public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2365  int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID;
2366  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash);
2367 
2368  Connection conn = connect();
2369 
2370  PreparedStatement preparedStatement = null;
2371  ResultSet resultSet = null;
2372  String sql = "SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?";
2373 
2374  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2375 
2376  try {
2377  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2378  preparedStatement.setString(1, normalizeValued);
2379  preparedStatement.setInt(2, referenceSetID);
2380  resultSet = preparedStatement.executeQuery();
2381  if (resultSet.next()) {
2382  String comment = resultSet.getString("comment");
2383  String hashFound = resultSet.getString("value");
2384  HashHitInfo found = new HashHitInfo(hashFound, "", "");
2385  found.addComment(comment);
2386  return found;
2387  } else {
2388  return null;
2389  }
2390  } catch (SQLException ex) {
2391  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2392  } finally {
2393  CentralRepoDbUtil.closeResultSet(resultSet);
2394  CentralRepoDbUtil.closeStatement(preparedStatement);
2395  CentralRepoDbUtil.closeConnection(conn);
2396  }
2397  }
2398 
2408  @Override
2409  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2410 
2411  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2412 
2413  Connection conn = connect();
2414 
2415  Long matchingInstances = 0L;
2416  PreparedStatement preparedStatement = null;
2417  ResultSet resultSet = null;
2418  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2419 
2420  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2421 
2422  try {
2423  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2424  preparedStatement.setString(1, normalizeValued);
2425  preparedStatement.setInt(2, referenceSetID);
2426  resultSet = preparedStatement.executeQuery();
2427  resultSet.next();
2428  matchingInstances = resultSet.getLong(1);
2429  } catch (SQLException ex) {
2430  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2431  } finally {
2432  CentralRepoDbUtil.closeResultSet(resultSet);
2433  CentralRepoDbUtil.closeStatement(preparedStatement);
2434  CentralRepoDbUtil.closeConnection(conn);
2435  }
2436 
2437  return 0 < matchingInstances;
2438  }
2439 
2448  @Override
2449  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2450 
2451  //this should be done here so that we can be certain that aType and value are valid before we proceed
2452  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2453 
2454  // TEMP: Only support file correlation type
2455  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2456  return false;
2457  }
2458 
2459  Connection conn = connect();
2460 
2461  Long badInstances = 0L;
2462  PreparedStatement preparedStatement = null;
2463  ResultSet resultSet = null;
2464  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2465 
2466  try {
2467  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
2468  preparedStatement.setString(1, normalizeValued);
2469  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2470  resultSet = preparedStatement.executeQuery();
2471  resultSet.next();
2472  badInstances = resultSet.getLong(1);
2473  } catch (SQLException ex) {
2474  throw new CentralRepoException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2475  } finally {
2476  CentralRepoDbUtil.closeResultSet(resultSet);
2477  CentralRepoDbUtil.closeStatement(preparedStatement);
2478  CentralRepoDbUtil.closeConnection(conn);
2479  }
2480 
2481  return 0 < badInstances;
2482  }
2483 
2492  @Override
2493  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2494  if (type == null) {
2495  throw new CentralRepoException("Correlation type is null");
2496  }
2497 
2498  if (instanceTableCallback == null) {
2499  throw new CentralRepoException("Callback interface is null");
2500  }
2501 
2502  Connection conn = connect();
2503  PreparedStatement preparedStatement = null;
2504  ResultSet resultSet = null;
2505  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2506  StringBuilder sql = new StringBuilder();
2507  sql.append("select * from ");
2508  sql.append(tableName);
2509 
2510  try {
2511  preparedStatement = conn.prepareStatement(sql.toString());
2512  resultSet = preparedStatement.executeQuery();
2513  instanceTableCallback.process(resultSet);
2514  } catch (SQLException ex) {
2515  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2516  } finally {
2517  CentralRepoDbUtil.closeResultSet(resultSet);
2518  CentralRepoDbUtil.closeStatement(preparedStatement);
2519  CentralRepoDbUtil.closeConnection(conn);
2520  }
2521  }
2522 
2532  @Override
2533  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2534  if (type == null) {
2535  throw new CentralRepoException("Correlation type is null");
2536  }
2537 
2538  if (instanceTableCallback == null) {
2539  throw new CentralRepoException("Callback interface is null");
2540  }
2541 
2542  if (whereClause == null) {
2543  throw new CentralRepoException("Where clause is null");
2544  }
2545 
2546  Connection conn = connect();
2547  PreparedStatement preparedStatement = null;
2548  ResultSet resultSet = null;
2549  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2550  StringBuilder sql = new StringBuilder(300);
2551  sql.append("select * from ")
2552  .append(tableName)
2553  .append(" WHERE ")
2554  .append(whereClause);
2555 
2556  try {
2557  preparedStatement = conn.prepareStatement(sql.toString());
2558  resultSet = preparedStatement.executeQuery();
2559  instanceTableCallback.process(resultSet);
2560  } catch (SQLException ex) {
2561  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2562  } finally {
2563  CentralRepoDbUtil.closeResultSet(resultSet);
2564  CentralRepoDbUtil.closeStatement(preparedStatement);
2565  CentralRepoDbUtil.closeConnection(conn);
2566  }
2567  }
2568 
2577  @Override
2578  public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2579 
2580  if (instanceTableCallback == null) {
2581  throw new CentralRepoException("Callback interface is null");
2582  }
2583 
2584  if (selectClause == null) {
2585  throw new CentralRepoException("Select clause is null");
2586  }
2587 
2588  Connection conn = connect();
2589  PreparedStatement preparedStatement = null;
2590  ResultSet resultSet = null;
2591  StringBuilder sql = new StringBuilder(300);
2592  sql.append("select ")
2593  .append(selectClause);
2594 
2595  try {
2596  preparedStatement = conn.prepareStatement(sql.toString());
2597  resultSet = preparedStatement.executeQuery();
2598  instanceTableCallback.process(resultSet);
2599  } catch (SQLException ex) {
2600  throw new CentralRepoException("Error running query", ex);
2601  } finally {
2602  CentralRepoDbUtil.closeResultSet(resultSet);
2603  CentralRepoDbUtil.closeStatement(preparedStatement);
2604  CentralRepoDbUtil.closeConnection(conn);
2605  }
2606  }
2607 
2608  @Override
2609  public void executeCommand(String sql, List<Object> params) throws CentralRepoException {
2610 
2611  try (Connection conn = connect();) {
2612 
2613  PreparedStatement preparedStatement = conn.prepareStatement(sql);
2614 
2615  // Fill in the params
2616  if (params != null) {
2617  int paramIndex = 1;
2618  for (Object param : params) {
2619  preparedStatement.setObject(paramIndex, param);
2620  paramIndex += 1;
2621  }
2622  }
2623  // execute the prepared statement
2624  preparedStatement.executeUpdate();
2625  } catch (SQLException ex) {
2626  throw new CentralRepoException(String.format("Error executing prepared statement for SQL %s", sql), ex);
2627  }
2628  }
2629 
2630  @Override
2631  public void executeQuery(String sql, List<Object> params, CentralRepositoryDbQueryCallback queryCallback) throws CentralRepoException {
2632  if (queryCallback == null) {
2633  throw new CentralRepoException("Query callback is null");
2634  }
2635 
2636  try (Connection conn = connect();) {
2637  PreparedStatement preparedStatement = conn.prepareStatement(sql);
2638 
2639  // fill in the params
2640  if (params != null) {
2641  int paramIndex = 1;
2642  for (Object param : params) {
2643  preparedStatement.setObject(paramIndex, param);
2644  paramIndex += 1;
2645  }
2646  }
2647  // execute query, and the callback to process result
2648  try (ResultSet resultSet = preparedStatement.executeQuery();) {
2649  queryCallback.process(resultSet);
2650  }
2651  } catch (SQLException ex) {
2652  throw new CentralRepoException(String.format("Error executing prepared statement for SQL query %s", sql), ex);
2653  }
2654  }
2655 
2656  @Override
2657  public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) throws CentralRepoException {
2658  if (eamOrg == null) {
2659  throw new CentralRepoException("EamOrganization is null");
2660  } else if (eamOrg.getOrgID() != -1) {
2661  throw new CentralRepoException("EamOrganization already has an ID");
2662  }
2663 
2664  Connection conn = connect();
2665  ResultSet generatedKeys = null;
2666  PreparedStatement preparedStatement = null;
2667  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2668  + getConflictClause();
2669 
2670  try {
2671  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2672  preparedStatement.setString(1, eamOrg.getName());
2673  preparedStatement.setString(2, eamOrg.getPocName());
2674  preparedStatement.setString(3, eamOrg.getPocEmail());
2675  preparedStatement.setString(4, eamOrg.getPocPhone());
2676 
2677  preparedStatement.executeUpdate();
2678  generatedKeys = preparedStatement.getGeneratedKeys();
2679  if (generatedKeys.next()) {
2680  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2681  return eamOrg;
2682  } else {
2683  throw new SQLException("Creating user failed, no ID obtained.");
2684  }
2685  } catch (SQLException ex) {
2686  throw new CentralRepoException("Error inserting new organization.", ex); // NON-NLS
2687  } finally {
2688  CentralRepoDbUtil.closeResultSet(generatedKeys);
2689  CentralRepoDbUtil.closeStatement(preparedStatement);
2690  CentralRepoDbUtil.closeConnection(conn);
2691  }
2692  }
2693 
2701  @Override
2702  public List<CentralRepoOrganization> getOrganizations() throws CentralRepoException {
2703  Connection conn = connect();
2704 
2705  List<CentralRepoOrganization> orgs = new ArrayList<>();
2706  PreparedStatement preparedStatement = null;
2707  ResultSet resultSet = null;
2708  String sql = "SELECT * FROM organizations";
2709 
2710  try {
2711  preparedStatement = conn.prepareStatement(sql);
2712  resultSet = preparedStatement.executeQuery();
2713  while (resultSet.next()) {
2714  orgs.add(getEamOrganizationFromResultSet(resultSet));
2715  }
2716  return orgs;
2717 
2718  } catch (SQLException ex) {
2719  throw new CentralRepoException("Error getting all organizations.", ex); // NON-NLS
2720  } finally {
2721  CentralRepoDbUtil.closeResultSet(resultSet);
2722  CentralRepoDbUtil.closeStatement(preparedStatement);
2723  CentralRepoDbUtil.closeConnection(conn);
2724  }
2725  }
2726 
2736  @Override
2737  public CentralRepoOrganization getOrganizationByID(int orgID) throws CentralRepoException {
2738  Connection conn = connect();
2739 
2740  PreparedStatement preparedStatement = null;
2741  ResultSet resultSet = null;
2742  String sql = "SELECT * FROM organizations WHERE id=?";
2743 
2744  try {
2745  preparedStatement = conn.prepareStatement(sql);
2746  preparedStatement.setInt(1, orgID);
2747  resultSet = preparedStatement.executeQuery();
2748  resultSet.next();
2749  return getEamOrganizationFromResultSet(resultSet);
2750 
2751  } catch (SQLException ex) {
2752  throw new CentralRepoException("Error getting organization by id.", ex); // NON-NLS
2753  } finally {
2754  CentralRepoDbUtil.closeResultSet(resultSet);
2755  CentralRepoDbUtil.closeStatement(preparedStatement);
2756  CentralRepoDbUtil.closeConnection(conn);
2757  }
2758  }
2759 
2769  @Override
2770  public CentralRepoOrganization getReferenceSetOrganization(int referenceSetID) throws CentralRepoException {
2771 
2772  CentralRepoFileSet globalSet = getReferenceSetByID(referenceSetID);
2773  if (globalSet == null) {
2774  throw new CentralRepoException("Reference set with ID " + referenceSetID + " not found");
2775  }
2776  return (getOrganizationByID(globalSet.getOrgID()));
2777  }
2778 
2786  private void testArgument(CentralRepoOrganization org) throws CentralRepoException {
2787  if (org == null) {
2788  throw new CentralRepoException("EamOrganization is null");
2789  } else if (org.getOrgID() == -1) {
2790  throw new CentralRepoException("Organization has -1 row ID");
2791  }
2792  }
2793 
2805  @Override
2806  public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException {
2807 
2808  String querySQL = "SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "'";
2809  try (Connection connection = connect();
2810  Statement statement = connection.createStatement();
2811  ResultSet resultSet = statement.executeQuery(querySQL);) {
2812 
2813  if (resultSet.next()) {
2814  return new CentralRepoExaminer(resultSet.getLong("id"), resultSet.getString("login_name"));
2815  } else {
2816  // Could not find this user in the Examiner table, add a row for it.
2817  try {
2818  String insertSQL;
2819  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
2820  case POSTGRESQL:
2821  insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')" + getConflictClause(); //NON-NLS
2822  break;
2823  case SQLITE:
2824  insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')"; //NON-NLS
2825  break;
2826  default:
2827  throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
2828  }
2829  statement.execute(insertSQL);
2830 
2831  // Query the table again to get the row for the user
2832  try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
2833  if (resultSet2.next()) {
2834  return new CentralRepoExaminer(resultSet2.getLong("id"), resultSet2.getString("login_name"));
2835  } else {
2836  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName);
2837  }
2838  }
2839 
2840  } catch (SQLException ex) {
2841  throw new CentralRepoException("Error inserting row in examiners", ex);
2842  }
2843  }
2844 
2845  } catch (SQLException ex) {
2846  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex);
2847  }
2848  }
2849 
2858  @Override
2859  public void updateOrganization(CentralRepoOrganization updatedOrganization) throws CentralRepoException {
2860  testArgument(updatedOrganization);
2861 
2862  Connection conn = connect();
2863  PreparedStatement preparedStatement = null;
2864  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2865  try {
2866  preparedStatement = conn.prepareStatement(sql);
2867  preparedStatement.setString(1, updatedOrganization.getName());
2868  preparedStatement.setString(2, updatedOrganization.getPocName());
2869  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2870  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2871  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2872  preparedStatement.executeUpdate();
2873  } catch (SQLException ex) {
2874  throw new CentralRepoException("Error updating organization.", ex); // NON-NLS
2875  } finally {
2876  CentralRepoDbUtil.closeStatement(preparedStatement);
2877  CentralRepoDbUtil.closeConnection(conn);
2878  }
2879  }
2880 
2881  @Override
2882  public void deleteOrganization(CentralRepoOrganization organizationToDelete) throws CentralRepoException {
2883  testArgument(organizationToDelete);
2884 
2885  Connection conn = connect();
2886  PreparedStatement checkIfUsedStatement = null;
2887  ResultSet resultSet = null;
2888  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2889  PreparedStatement deleteOrgStatement = null;
2890  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2891  try {
2892  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2893  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2894  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2895  resultSet = checkIfUsedStatement.executeQuery();
2896  resultSet.next();
2897  if (resultSet.getLong(1) > 0) {
2898  throw new CentralRepoException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2899  }
2900  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2901  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2902  deleteOrgStatement.executeUpdate();
2903  } catch (SQLException ex) {
2904  throw new CentralRepoException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2905  } finally {
2906  CentralRepoDbUtil.closeResultSet(resultSet);
2907  CentralRepoDbUtil.closeStatement(checkIfUsedStatement);
2908  CentralRepoDbUtil.closeStatement(deleteOrgStatement);
2909  CentralRepoDbUtil.closeConnection(conn);
2910  }
2911  }
2912 
2922  @Override
2923  public int newReferenceSet(CentralRepoFileSet eamGlobalSet) throws CentralRepoException {
2924  if (eamGlobalSet == null) {
2925  throw new CentralRepoException("EamGlobalSet is null");
2926  }
2927 
2928  if (eamGlobalSet.getFileKnownStatus() == null) {
2929  throw new CentralRepoException("File known status on the EamGlobalSet is null");
2930  }
2931 
2932  if (eamGlobalSet.getType() == null) {
2933  throw new CentralRepoException("Type on the EamGlobalSet is null");
2934  }
2935 
2936  Connection conn = connect();
2937 
2938  PreparedStatement preparedStatement1 = null;
2939  PreparedStatement preparedStatement2 = null;
2940  ResultSet resultSet = null;
2941  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2942  + getConflictClause();
2943  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2944 
2945  try {
2946  preparedStatement1 = conn.prepareStatement(sql1);
2947  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2948  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2949  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2950  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2951  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2952  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2953  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2954 
2955  preparedStatement1.executeUpdate();
2956 
2957  preparedStatement2 = conn.prepareStatement(sql2);
2958  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2959  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2960  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2961  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2962 
2963  resultSet = preparedStatement2.executeQuery();
2964  resultSet.next();
2965  return resultSet.getInt("id");
2966 
2967  } catch (SQLException ex) {
2968  throw new CentralRepoException("Error inserting new global set.", ex); // NON-NLS
2969  } finally {
2970  CentralRepoDbUtil.closeResultSet(resultSet);
2971  CentralRepoDbUtil.closeStatement(preparedStatement1);
2972  CentralRepoDbUtil.closeStatement(preparedStatement2);
2973  CentralRepoDbUtil.closeConnection(conn);
2974  }
2975  }
2976 
2986  @Override
2987  public CentralRepoFileSet getReferenceSetByID(int referenceSetID) throws CentralRepoException {
2988  Connection conn = connect();
2989 
2990  PreparedStatement preparedStatement1 = null;
2991  ResultSet resultSet = null;
2992  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2993 
2994  try {
2995  preparedStatement1 = conn.prepareStatement(sql1);
2996  preparedStatement1.setInt(1, referenceSetID);
2997  resultSet = preparedStatement1.executeQuery();
2998  if (resultSet.next()) {
2999  return getEamGlobalSetFromResultSet(resultSet);
3000  } else {
3001  return null;
3002  }
3003 
3004  } catch (SQLException ex) {
3005  throw new CentralRepoException("Error getting reference set by id.", ex); // NON-NLS
3006  } finally {
3007  CentralRepoDbUtil.closeResultSet(resultSet);
3008  CentralRepoDbUtil.closeStatement(preparedStatement1);
3009  CentralRepoDbUtil.closeConnection(conn);
3010  }
3011  }
3012 
3022  @Override
3023  public List<CentralRepoFileSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3024 
3025  if (correlationType == null) {
3026  throw new CentralRepoException("Correlation type is null");
3027  }
3028 
3029  List<CentralRepoFileSet> results = new ArrayList<>();
3030  Connection conn = connect();
3031 
3032  PreparedStatement preparedStatement1 = null;
3033  ResultSet resultSet = null;
3034  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
3035 
3036  try {
3037  preparedStatement1 = conn.prepareStatement(sql1);
3038  resultSet = preparedStatement1.executeQuery();
3039  while (resultSet.next()) {
3040  results.add(getEamGlobalSetFromResultSet(resultSet));
3041  }
3042 
3043  } catch (SQLException ex) {
3044  throw new CentralRepoException("Error getting reference sets.", ex); // NON-NLS
3045  } finally {
3046  CentralRepoDbUtil.closeResultSet(resultSet);
3047  CentralRepoDbUtil.closeStatement(preparedStatement1);
3048  CentralRepoDbUtil.closeConnection(conn);
3049  }
3050  return results;
3051  }
3052 
3062  @Override
3063  public void addReferenceInstance(CentralRepoFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3064  if (eamGlobalFileInstance.getKnownStatus() == null) {
3065  throw new CentralRepoException("Known status of EamGlobalFileInstance is null");
3066  }
3067  if (correlationType == null) {
3068  throw new CentralRepoException("Correlation type is null");
3069  }
3070 
3071  Connection conn = connect();
3072 
3073  PreparedStatement preparedStatement = null;
3074 
3075  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3076  + getConflictClause();
3077 
3078  try {
3079  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(correlationType)));
3080  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
3081  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
3082  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
3083  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
3084  preparedStatement.executeUpdate();
3085  } catch (SQLException ex) {
3086  throw new CentralRepoException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
3087  } finally {
3088  CentralRepoDbUtil.closeStatement(preparedStatement);
3089  CentralRepoDbUtil.closeConnection(conn);
3090  }
3091  }
3092 
3105  @Override
3106  public boolean referenceSetExists(String referenceSetName, String version) throws CentralRepoException {
3107  Connection conn = connect();
3108 
3109  PreparedStatement preparedStatement1 = null;
3110  ResultSet resultSet = null;
3111  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
3112 
3113  try {
3114  preparedStatement1 = conn.prepareStatement(sql1);
3115  preparedStatement1.setString(1, referenceSetName);
3116  preparedStatement1.setString(2, version);
3117  resultSet = preparedStatement1.executeQuery();
3118  return (resultSet.next());
3119 
3120  } catch (SQLException ex) {
3121  throw new CentralRepoException("Error testing whether reference set exists (name: " + referenceSetName
3122  + " version: " + version, ex); // NON-NLS
3123  } finally {
3124  CentralRepoDbUtil.closeResultSet(resultSet);
3125  CentralRepoDbUtil.closeStatement(preparedStatement1);
3126  CentralRepoDbUtil.closeConnection(conn);
3127  }
3128  }
3129 
3135  @Override
3136  public void bulkInsertReferenceTypeEntries(Set<CentralRepoFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws CentralRepoException {
3137  if (contentType == null) {
3138  throw new CentralRepoException("Correlation type is null");
3139  }
3140  if (globalInstances == null) {
3141  throw new CentralRepoException("Null set of EamGlobalFileInstance");
3142  }
3143 
3144  Connection conn = connect();
3145 
3146  PreparedStatement bulkPs = null;
3147  try {
3148  conn.setAutoCommit(false);
3149 
3150  // FUTURE: have a separate global_files table for each Type.
3151  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3152  + getConflictClause();
3153 
3154  bulkPs = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(contentType)));
3155 
3156  for (CentralRepoFileInstance globalInstance : globalInstances) {
3157  if (globalInstance.getKnownStatus() == null) {
3158  throw new CentralRepoException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
3159  }
3160 
3161  bulkPs.setInt(1, globalInstance.getGlobalSetID());
3162  bulkPs.setString(2, globalInstance.getMD5Hash());
3163  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
3164  bulkPs.setString(4, globalInstance.getComment());
3165  bulkPs.addBatch();
3166  }
3167 
3168  bulkPs.executeBatch();
3169  conn.commit();
3170  } catch (SQLException | CentralRepoException ex) {
3171  try {
3172  conn.rollback();
3173  } catch (SQLException ex2) {
3174  // We're alredy in an error state
3175  }
3176  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
3177  } finally {
3178  CentralRepoDbUtil.closeStatement(bulkPs);
3179  CentralRepoDbUtil.closeConnection(conn);
3180  }
3181  }
3182 
3193  @Override
3194  public List<CentralRepoFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws CentralRepoException, CorrelationAttributeNormalizationException {
3195  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
3196 
3197  Connection conn = connect();
3198 
3199  List<CentralRepoFileInstance> globalFileInstances = new ArrayList<>();
3200  PreparedStatement preparedStatement1 = null;
3201  ResultSet resultSet = null;
3202  String sql1 = "SELECT * FROM %s WHERE value=?";
3203 
3204  try {
3205  preparedStatement1 = conn.prepareStatement(String.format(sql1, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
3206  preparedStatement1.setString(1, normalizeValued);
3207  resultSet = preparedStatement1.executeQuery();
3208  while (resultSet.next()) {
3209  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
3210  }
3211 
3212  } catch (SQLException ex) {
3213  throw new CentralRepoException("Error getting reference instances by type and value.", ex); // NON-NLS
3214  } finally {
3215  CentralRepoDbUtil.closeResultSet(resultSet);
3216  CentralRepoDbUtil.closeStatement(preparedStatement1);
3217  CentralRepoDbUtil.closeConnection(conn);
3218  }
3219 
3220  return globalFileInstances;
3221  }
3222 
3232  @Override
3233  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3234  if (newType == null) {
3235  throw new CentralRepoException("Correlation type is null");
3236  }
3237  int typeId;
3238  if (-1 == newType.getId()) {
3239  typeId = newCorrelationTypeNotKnownId(newType);
3240  } else {
3241  typeId = newCorrelationTypeKnownId(newType);
3242  }
3243 
3244  synchronized (typeCache) {
3245  typeCache.put(newType.getId(), newType);
3246  }
3247  return typeId;
3248  }
3249 
3260  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3261  Connection conn = connect();
3262 
3263  PreparedStatement preparedStatement = null;
3264  PreparedStatement preparedStatementQuery = null;
3265  ResultSet resultSet = null;
3266  int typeId = 0;
3267  String insertSql;
3268  String querySql;
3269  // if we have a known ID, use it, if not (is -1) let the db assign it.
3270  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
3271 
3272  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3273 
3274  try {
3275  preparedStatement = conn.prepareStatement(insertSql);
3276 
3277  preparedStatement.setString(1, newType.getDisplayName());
3278  preparedStatement.setString(2, newType.getDbTableName());
3279  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
3280  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
3281 
3282  preparedStatement.executeUpdate();
3283 
3284  preparedStatementQuery = conn.prepareStatement(querySql);
3285  preparedStatementQuery.setString(1, newType.getDisplayName());
3286  preparedStatementQuery.setString(2, newType.getDbTableName());
3287 
3288  resultSet = preparedStatementQuery.executeQuery();
3289  if (resultSet.next()) {
3290  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3291  typeId = correlationType.getId();
3292  }
3293  } catch (SQLException ex) {
3294  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3295  } finally {
3296  CentralRepoDbUtil.closeResultSet(resultSet);
3297  CentralRepoDbUtil.closeStatement(preparedStatement);
3298  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3299  CentralRepoDbUtil.closeConnection(conn);
3300  }
3301  return typeId;
3302  }
3303 
3313  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3314  Connection conn = connect();
3315 
3316  PreparedStatement preparedStatement = null;
3317  PreparedStatement preparedStatementQuery = null;
3318  ResultSet resultSet = null;
3319  int typeId = 0;
3320  String insertSql;
3321  String querySql;
3322  // if we have a known ID, use it, if not (is -1) let the db assign it.
3323  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
3324 
3325  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3326 
3327  try {
3328  preparedStatement = conn.prepareStatement(insertSql);
3329 
3330  preparedStatement.setInt(1, newType.getId());
3331  preparedStatement.setString(2, newType.getDisplayName());
3332  preparedStatement.setString(3, newType.getDbTableName());
3333  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
3334  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
3335 
3336  preparedStatement.executeUpdate();
3337 
3338  preparedStatementQuery = conn.prepareStatement(querySql);
3339  preparedStatementQuery.setString(1, newType.getDisplayName());
3340  preparedStatementQuery.setString(2, newType.getDbTableName());
3341 
3342  resultSet = preparedStatementQuery.executeQuery();
3343  if (resultSet.next()) {
3344  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3345  typeId = correlationType.getId();
3346  }
3347  } catch (SQLException ex) {
3348  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3349  } finally {
3350  CentralRepoDbUtil.closeResultSet(resultSet);
3351  CentralRepoDbUtil.closeStatement(preparedStatement);
3352  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3353  CentralRepoDbUtil.closeConnection(conn);
3354  }
3355  return typeId;
3356  }
3357 
3358  @Override
3359  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws CentralRepoException {
3360 
3361  synchronized (typeCache) {
3362  if (isCRTypeCacheInitialized == false) {
3363  getCorrelationTypesFromCr();
3364  }
3365  return new ArrayList<>(typeCache.asMap().values());
3366  }
3367  }
3368 
3378  @Override
3379  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws CentralRepoException {
3380  Connection conn = connect();
3381 
3382  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3383  PreparedStatement preparedStatement = null;
3384  ResultSet resultSet = null;
3385  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
3386 
3387  try {
3388  preparedStatement = conn.prepareStatement(sql);
3389  resultSet = preparedStatement.executeQuery();
3390  while (resultSet.next()) {
3391  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3392  }
3393  return aTypes;
3394 
3395  } catch (SQLException ex) {
3396  throw new CentralRepoException("Error getting enabled correlation types.", ex); // NON-NLS
3397  } finally {
3398  CentralRepoDbUtil.closeResultSet(resultSet);
3399  CentralRepoDbUtil.closeStatement(preparedStatement);
3400  CentralRepoDbUtil.closeConnection(conn);
3401  }
3402  }
3403 
3413  @Override
3414  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws CentralRepoException {
3415  Connection conn = connect();
3416 
3417  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3418  PreparedStatement preparedStatement = null;
3419  ResultSet resultSet = null;
3420  String sql = "SELECT * FROM correlation_types WHERE supported=1";
3421 
3422  try {
3423  preparedStatement = conn.prepareStatement(sql);
3424  resultSet = preparedStatement.executeQuery();
3425  while (resultSet.next()) {
3426  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3427  }
3428  return aTypes;
3429 
3430  } catch (SQLException ex) {
3431  throw new CentralRepoException("Error getting supported correlation types.", ex); // NON-NLS
3432  } finally {
3433  CentralRepoDbUtil.closeResultSet(resultSet);
3434  CentralRepoDbUtil.closeStatement(preparedStatement);
3435  CentralRepoDbUtil.closeConnection(conn);
3436  }
3437  }
3438 
3446  @Override
3447  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws CentralRepoException {
3448  Connection conn = connect();
3449 
3450  PreparedStatement preparedStatement = null;
3451  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3452 
3453  try {
3454  preparedStatement = conn.prepareStatement(sql);
3455  preparedStatement.setString(1, aType.getDisplayName());
3456  preparedStatement.setString(2, aType.getDbTableName());
3457  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3458  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3459  preparedStatement.setInt(5, aType.getId());
3460  preparedStatement.executeUpdate();
3461  synchronized (typeCache) {
3462  typeCache.put(aType.getId(), aType);
3463  }
3464  } catch (SQLException ex) {
3465  throw new CentralRepoException("Error updating correlation type.", ex); // NON-NLS
3466  } finally {
3467  CentralRepoDbUtil.closeStatement(preparedStatement);
3468  CentralRepoDbUtil.closeConnection(conn);
3469  }
3470 
3471  }
3472 
3482  @Override
3483  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws CentralRepoException {
3484  try {
3485  synchronized (typeCache) {
3486  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3487  }
3488  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3489  //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
3490  return null;
3491  } catch (ExecutionException ex) {
3492  throw new CentralRepoException("Error getting correlation type", ex);
3493  }
3494  }
3495 
3505  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws CentralRepoException {
3506  Connection conn = connect();
3507 
3508  CorrelationAttributeInstance.Type aType;
3509  PreparedStatement preparedStatement = null;
3510  ResultSet resultSet = null;
3511  String sql = "SELECT * FROM correlation_types WHERE id=?";
3512 
3513  try {
3514  preparedStatement = conn.prepareStatement(sql);
3515  preparedStatement.setInt(1, typeId);
3516  resultSet = preparedStatement.executeQuery();
3517  if (resultSet.next()) {
3518  aType = getCorrelationTypeFromResultSet(resultSet);
3519  return aType;
3520  } else {
3521  throw new CentralRepoException("Failed to find entry for correlation type ID = " + typeId);
3522  }
3523 
3524  } catch (SQLException ex) {
3525  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
3526  } finally {
3527  CentralRepoDbUtil.closeResultSet(resultSet);
3528  CentralRepoDbUtil.closeStatement(preparedStatement);
3529  CentralRepoDbUtil.closeConnection(conn);
3530  }
3531  }
3532 
3539  private void getCorrelationTypesFromCr() throws CentralRepoException {
3540 
3541  // clear out the cache
3542  synchronized (typeCache) {
3543  typeCache.invalidateAll();
3544  isCRTypeCacheInitialized = false;
3545  }
3546 
3547  String sql = "SELECT * FROM correlation_types";
3548  try (Connection conn = connect();
3549  PreparedStatement preparedStatement = conn.prepareStatement(sql);
3550  ResultSet resultSet = preparedStatement.executeQuery();) {
3551 
3552  synchronized (typeCache) {
3553  while (resultSet.next()) {
3554  CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
3555  typeCache.put(aType.getId(), aType);
3556  }
3557  isCRTypeCacheInitialized = true;
3558  }
3559  } catch (SQLException ex) {
3560  throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS
3561  }
3562  }
3563 
3574  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3575  if (null == resultSet) {
3576  return null;
3577  }
3578 
3579  CentralRepoOrganization eamOrg = null;
3580 
3581  resultSet.getInt("org_id");
3582  if (!resultSet.wasNull()) {
3583 
3584  eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3585  resultSet.getString("org_name"),
3586  resultSet.getString("poc_name"),
3587  resultSet.getString("poc_email"),
3588  resultSet.getString("poc_phone"));
3589  }
3590 
3591  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3592  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3593  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3594 
3595  return eamCase;
3596  }
3597 
3598  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3599  if (null == resultSet) {
3600  return null;
3601  }
3602 
3603  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3604  resultSet.getInt("case_id"),
3605  resultSet.getInt("id"),
3606  resultSet.getString("device_id"),
3607  resultSet.getString("name"),
3608  resultSet.getLong("datasource_obj_id"),
3609  resultSet.getString("md5"),
3610  resultSet.getString("sha1"),
3611  resultSet.getString("sha256")
3612  );
3613 
3614  return eamDataSource;
3615  }
3616 
3617  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws CentralRepoException, SQLException {
3618  if (null == resultSet) {
3619  return null;
3620  }
3621 
3622  CorrelationAttributeInstance.Type eamArtifactType = new CorrelationAttributeInstance.Type(
3623  resultSet.getInt("id"),
3624  resultSet.getString("display_name"),
3625  resultSet.getString("db_table_name"),
3626  resultSet.getBoolean("supported"),
3627  resultSet.getBoolean("enabled")
3628  );
3629 
3630  return eamArtifactType;
3631  }
3632 
3643  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3644  if (null == resultSet) {
3645  return null;
3646  }
3647 
3648  CentralRepoOrganization eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3649  resultSet.getString("org_name"),
3650  resultSet.getString("poc_name"),
3651  resultSet.getString("poc_email"),
3652  resultSet.getString("poc_phone"));
3653 
3654  return new CorrelationAttributeInstance(
3655  aType,
3656  resultSet.getString("value"),
3657  resultSet.getInt("instance_id"),
3658  new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3659  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3660  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3661  new CorrelationDataSource(
3662  resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3663  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3664  resultSet.getString("file_path"),
3665  resultSet.getString("comment"),
3666  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3667  resultSet.getLong("file_obj_id"));
3668  }
3669 
3670  private CentralRepoOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3671  if (null == resultSet) {
3672  return null;
3673  }
3674 
3675  return new CentralRepoOrganization(
3676  resultSet.getInt("id"),
3677  resultSet.getString("org_name"),
3678  resultSet.getString("poc_name"),
3679  resultSet.getString("poc_email"),
3680  resultSet.getString("poc_phone")
3681  );
3682  }
3683 
3684  private CentralRepoFileSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException {
3685  if (null == resultSet) {
3686  return null;
3687  }
3688 
3689  return new CentralRepoFileSet(
3690  resultSet.getInt("id"),
3691  resultSet.getInt("org_id"),
3692  resultSet.getString("set_name"),
3693  resultSet.getString("version"),
3694  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3695  resultSet.getBoolean("read_only"),
3696  CentralRepository.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3697  LocalDate.parse(resultSet.getString("import_date"))
3698  );
3699  }
3700 
3701  private CentralRepoFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3702  if (null == resultSet) {
3703  return null;
3704  }
3705 
3706  return new CentralRepoFileInstance(
3707  resultSet.getInt("id"),
3708  resultSet.getInt("reference_set_id"),
3709  resultSet.getString("value"),
3710  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3711  resultSet.getString("comment")
3712  );
3713  }
3714 
3715  private String getPlatformSpecificInsertSQL(String sql) throws CentralRepoException {
3716 
3717  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
3718  case POSTGRESQL:
3719  return "INSERT " + sql + " ON CONFLICT DO NOTHING"; //NON-NLS
3720  case SQLITE:
3721  return "INSERT OR IGNORE " + sql;
3722 
3723  default:
3724  throw new CentralRepoException("Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
3725  }
3726  }
3727 
3738  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3739 
3745  @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.",
3746  "# {0} - minorVersion",
3747  "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
3748  "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
3749  "# {0} - majorVersion",
3750  "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
3751  "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
3752  "# {0} - platformName",
3753  "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
3754  @Override
3755  public void upgradeSchema() throws CentralRepoException, SQLException, IncompatibleCentralRepoException {
3756 
3757  ResultSet resultSet = null;
3758  Statement statement = null;
3759  PreparedStatement preparedStatement = null;
3760  Connection conn = null;
3761  CentralRepoPlatforms selectedPlatform = null;
3762  try {
3763 
3764  conn = connect(false);
3765  conn.setAutoCommit(false);
3766  statement = conn.createStatement();
3767  selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
3768  int minorVersion = 0;
3769  String minorVersionStr = null;
3770  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
3771  if (resultSet.next()) {
3772  minorVersionStr = resultSet.getString("value");
3773  try {
3774  minorVersion = Integer.parseInt(minorVersionStr);
3775  } catch (NumberFormatException ex) {
3776  throw new CentralRepoException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
3777  }
3778  } else {
3779  throw new CentralRepoException("Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
3780  }
3781 
3782  int majorVersion = 0;
3783  String majorVersionStr = null;
3784  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "'");
3785  if (resultSet.next()) {
3786  majorVersionStr = resultSet.getString("value");
3787  try {
3788  majorVersion = Integer.parseInt(majorVersionStr);
3789  } catch (NumberFormatException ex) {
3790  throw new CentralRepoException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
3791  }
3792  } else {
3793  throw new CentralRepoException("Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
3794  }
3795 
3796  /*
3797  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3798  * 4.10.0. The consequence of the bug is that the schema version
3799  * number is always reset to 1.0 or 1.1 if a Central Repository is
3800  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3801  * there is an effort in updates to 1.2 and greater to not retry
3802  * schema updates that may already have been done once.
3803  */
3804  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3805 
3806  //compare the major versions for compatability
3807  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3808  //because it is specific to case db schema versions only supporting major versions greater than 1
3809  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3810  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3811  }
3812  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3813  logger.log(Level.INFO, "Central Repository is up to date");
3814  return;
3815  }
3816  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3817  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3818  return;
3819  }
3820 
3821  /*
3822  * Update to 1.1
3823  */
3824  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3825  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3826  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3827  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3828 
3829  // There's an outide chance that the user has already made an organization with the default name,
3830  // and the default org being missing will not impact any database operations, so continue on
3831  // regardless of whether this succeeds.
3832  CentralRepoDbUtil.insertDefaultOrganization(conn);
3833  }
3834 
3835  /*
3836  * Update to 1.2
3837  */
3838  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3839  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3840 
3841  final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
3842  final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
3843  final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
3844  final String addValueIndexTemplate = RdbmsCentralRepoFactory.getAddValueIndexTemplate();
3845  final String addKnownStatusIndexTemplate = RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate();
3846  final String addObjectIdIndexTemplate = RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate();
3847 
3848  final String addAttributeSql;
3849  //get the data base specific code for creating a new _instance table
3850  switch (selectedPlatform) {
3851  case POSTGRESQL:
3852  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3853  break;
3854  case SQLITE:
3855  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3856  break;
3857  default:
3858  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3859  }
3860 
3861  final String dataSourcesTableName = "data_sources";
3862  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3863  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3864  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3865  }
3866  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3867  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3868  List<String> instaceTablesToAdd = new ArrayList<>();
3869  //update central repository to be able to store new correlation attributes
3870  final String wirelessNetworksDbTableName = "wireless_networks";
3871  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3872  final String macAddressDbTableName = "mac_address";
3873  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3874  final String imeiNumberDbTableName = "imei_number";
3875  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3876  final String iccidNumberDbTableName = "iccid_number";
3877  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3878  final String imsiNumberDbTableName = "imsi_number";
3879  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3880 
3881  //add the wireless_networks attribute to the correlation_types table
3882  preparedStatement = conn.prepareStatement(addAttributeSql);
3883  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3884  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3885  preparedStatement.setString(3, wirelessNetworksDbTableName);
3886  preparedStatement.setInt(4, 1);
3887  preparedStatement.setInt(5, 1);
3888  preparedStatement.execute();
3889 
3890  //add the mac_address attribute to the correlation_types table
3891  preparedStatement = conn.prepareStatement(addAttributeSql);
3892  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3893  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3894  preparedStatement.setString(3, macAddressDbTableName);
3895  preparedStatement.setInt(4, 1);
3896  preparedStatement.setInt(5, 1);
3897  preparedStatement.execute();
3898 
3899  //add the imei_number attribute to the correlation_types table
3900  preparedStatement = conn.prepareStatement(addAttributeSql);
3901  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3902  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3903  preparedStatement.setString(3, imeiNumberDbTableName);
3904  preparedStatement.setInt(4, 1);
3905  preparedStatement.setInt(5, 1);
3906  preparedStatement.execute();
3907 
3908  //add the imsi_number attribute to the correlation_types table
3909  preparedStatement = conn.prepareStatement(addAttributeSql);
3910  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3911  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3912  preparedStatement.setString(3, imsiNumberDbTableName);
3913  preparedStatement.setInt(4, 1);
3914  preparedStatement.setInt(5, 1);
3915  preparedStatement.execute();
3916 
3917  //add the iccid_number attribute to the correlation_types table
3918  preparedStatement = conn.prepareStatement(addAttributeSql);
3919  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3920  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3921  preparedStatement.setString(3, iccidNumberDbTableName);
3922  preparedStatement.setInt(4, 1);
3923  preparedStatement.setInt(5, 1);
3924  preparedStatement.execute();
3925 
3926  //create a new _instances tables and add indexes for their columns
3927  for (String tableName : instaceTablesToAdd) {
3928  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3929  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3930  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3931  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3932  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3933  }
3934 
3935  //add file_obj_id column to _instances table which do not already have it
3936  String instance_type_dbname;
3937  final String objectIdColumnName = "file_obj_id";
3938  for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
3939  instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
3940  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3941  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3942  }
3943  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3944  }
3945 
3946  /*
3947  * Add hash columns to the data_sources table.
3948  */
3949  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3950  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3951  }
3952  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3953  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3954  }
3955  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3956  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3957  }
3958 
3959  /*
3960  * Drop the db_info table and add it back in with the name
3961  * column having a UNIQUE constraint. The name column could now
3962  * be used as the primary key, but the essentially useless id
3963  * column is retained for the sake of backwards compatibility.
3964  * Note that the creation schema version number is set to 0.0 to
3965  * indicate that it is unknown.
3966  */
3967  String creationMajorVer;
3968  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3969  if (resultSet.next()) {
3970  creationMajorVer = resultSet.getString("value");
3971  } else {
3972  creationMajorVer = "0";
3973  }
3974  String creationMinorVer;
3975  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3976  if (resultSet.next()) {
3977  creationMinorVer = resultSet.getString("value");
3978  } else {
3979  creationMinorVer = "0";
3980  }
3981  statement.execute("DROP TABLE db_info");
3982  if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
3983  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3984  } else {
3985  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3986  }
3987  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3988  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3989  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3990  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3991  }
3992  /*
3993  * Update to 1.3
3994  */
3995  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3996  switch (selectedPlatform) {
3997  case POSTGRESQL:
3998  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3999  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
4000  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
4001 
4002  break;
4003  case SQLITE:
4004  statement.execute("DROP INDEX IF EXISTS data_sources_name");
4005  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
4006  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
4007  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
4008  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
4009  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
4010  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
4011  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
4012  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
4013  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesNameIndexStatement());
4014  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesObjectIdIndexStatement());
4015  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
4016  statement.execute("DROP TABLE old_data_sources");
4017  break;
4018  default:
4019  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
4020  }
4021  }
4022 
4023  // Upgrade to 1.4
4024  (new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
4025 
4026  // Upgrade to 1.5
4027  (new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);
4028 
4029  // Upgrade to 1.6
4030  (new CentralRepoDbUpgrader15To16()).upgradeSchema(dbSchemaVersion, conn);
4031 
4032  updateSchemaVersion(conn);
4033  conn.commit();
4034  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
4035  } catch (SQLException | CentralRepoException ex) {
4036  try {
4037  if (conn != null) {
4038  conn.rollback();
4039  }
4040  } catch (SQLException ex2) {
4041  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
4042  }
4043  throw ex;
4044  } finally {
4045  CentralRepoDbUtil.closeResultSet(resultSet);
4046  CentralRepoDbUtil.closeStatement(preparedStatement);
4047  CentralRepoDbUtil.closeStatement(statement);
4048  CentralRepoDbUtil.closeConnection(conn);
4049  }
4050  }
4051 
4052 }
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
CentralRepoAccount getOrCreateAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)

Copyright © 2012-2021 Basis Technology. Generated on: Thu Sep 30 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.