Autopsy  4.17.0
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-2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.centralrepository.datamodel;
20 
21 import com.google.common.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import com.google.common.cache.CacheLoader;
24 import java.net.UnknownHostException;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Collection;
28 import java.util.LinkedHashSet;
29 import java.util.stream.Collectors;
30 import java.sql.Connection;
31 import java.sql.PreparedStatement;
32 import java.sql.ResultSet;
33 import java.sql.SQLException;
34 import java.sql.Statement;
35 import java.sql.Types;
36 import java.time.LocalDate;
37 import java.util.Arrays;
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.ExecutionException;
42 import java.util.concurrent.TimeUnit;
43 import java.util.logging.Level;
44 import org.apache.commons.lang3.tuple.Pair;
45 import org.openide.util.NbBundle.Messages;
48 import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil.updateSchemaVersion;
52 import org.sleuthkit.datamodel.Account;
53 import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
54 import org.sleuthkit.datamodel.HashHitInfo;
55 import org.sleuthkit.datamodel.InvalidAccountIDException;
56 import org.sleuthkit.datamodel.SleuthkitCase;
57 import org.sleuthkit.datamodel.TskData;
58 
64 abstract class RdbmsCentralRepo implements CentralRepository {
65 
66  private final static Logger logger = Logger.getLogger(RdbmsCentralRepo.class.getName());
67  static final String SCHEMA_MAJOR_VERSION_KEY = "SCHEMA_VERSION";
68  static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
69  static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
70  static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
71  static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 5);
72 
73  protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
74 
75  private int bulkArtifactsCount;
76  protected int bulkArtifactsThreshold;
77  private final Map<String, Collection<CorrelationAttributeInstance>> bulkArtifacts;
78  private static final int CASE_CACHE_TIMEOUT = 5;
79  private static final int DATA_SOURCE_CACHE_TIMEOUT = 5;
80  private static final int ACCOUNTS_CACHE_TIMEOUT = 5;
81  private static final Cache<String, CentralRepoAccountType> accountTypesCache = CacheBuilder.newBuilder().build();
82  private static final Cache<Pair<CentralRepoAccountType, String>, CentralRepoAccount> accountsCache = CacheBuilder.newBuilder()
83  .expireAfterWrite(ACCOUNTS_CACHE_TIMEOUT, TimeUnit.MINUTES).
84  build();
85 
86  private boolean isCRTypeCacheInitialized;
87  private static final Cache<Integer, CorrelationAttributeInstance.Type> typeCache = CacheBuilder.newBuilder().build();
88  private static final Cache<String, CorrelationCase> caseCacheByUUID = CacheBuilder.newBuilder()
89  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
90  build();
91  private static final Cache<Integer, CorrelationCase> caseCacheById = CacheBuilder.newBuilder()
92  .expireAfterWrite(CASE_CACHE_TIMEOUT, TimeUnit.MINUTES).
93  build();
94  private static final Cache<String, CorrelationDataSource> dataSourceCacheByDsObjectId = CacheBuilder.newBuilder()
95  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
96  build();
97  private static final Cache<String, CorrelationDataSource> dataSourceCacheById = CacheBuilder.newBuilder()
98  .expireAfterWrite(DATA_SOURCE_CACHE_TIMEOUT, TimeUnit.MINUTES).
99  build();
100  // Maximum length for the value column in the instance tables
101  static final int MAX_VALUE_LENGTH = 256;
102 
103  // number of instances to keep in bulk queue before doing an insert.
104  // Update Test code if this changes. It's hard coded there.
105  static final int DEFAULT_BULK_THRESHHOLD = 1000;
106 
107  private static final int QUERY_STR_MAX_LEN = 1000;
108 
114  protected RdbmsCentralRepo() throws CentralRepoException {
115  isCRTypeCacheInitialized = false;
116  bulkArtifactsCount = 0;
117  bulkArtifacts = new HashMap<>();
118 
119  defaultCorrelationTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
120  defaultCorrelationTypes.forEach((type) -> {
121  bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(type), new ArrayList<>());
122  });
123  }
124 
128  protected abstract Connection connect(boolean foreignKeys) throws CentralRepoException;
129 
133  protected abstract Connection connect() throws CentralRepoException;
134 
138  protected abstract Connection getEphemeralConnection();
139 
148  @Override
149  public void newDbInfo(String name, String value) throws CentralRepoException {
150  Connection conn = connect();
151 
152  PreparedStatement preparedStatement = null;
153  String sql = "INSERT INTO db_info (name, value) VALUES (?, ?) "
154  + getConflictClause();
155  try {
156  preparedStatement = conn.prepareStatement(sql);
157  preparedStatement.setString(1, name);
158  preparedStatement.setString(2, value);
159  preparedStatement.executeUpdate();
160  } catch (SQLException ex) {
161  throw new CentralRepoException("Error adding new name/value pair to db_info.", ex);
162  } finally {
163  CentralRepoDbUtil.closeStatement(preparedStatement);
164  CentralRepoDbUtil.closeConnection(conn);
165  }
166 
167  }
168 
169  @Override
170  public void addDataSourceObjectId(int rowId, long dataSourceObjectId) throws CentralRepoException {
171  Connection conn = connect();
172  PreparedStatement preparedStatement = null;
173  String sql = "UPDATE data_sources SET datasource_obj_id=? WHERE id=?";
174  try {
175  preparedStatement = conn.prepareStatement(sql);
176  preparedStatement.setLong(1, dataSourceObjectId);
177  preparedStatement.setInt(2, rowId);
178  preparedStatement.executeUpdate();
179  } catch (SQLException ex) {
180  throw new CentralRepoException("Error updating data source object id for data_sources row " + rowId, ex);
181  } finally {
182  CentralRepoDbUtil.closeStatement(preparedStatement);
183  CentralRepoDbUtil.closeConnection(conn);
184  }
185  }
186 
196  @Override
197  public String getDbInfo(String name) throws CentralRepoException {
198  Connection conn = connect();
199 
200  PreparedStatement preparedStatement = null;
201  ResultSet resultSet = null;
202  String value = null;
203  String sql = "SELECT value FROM db_info WHERE name=?";
204  try {
205  preparedStatement = conn.prepareStatement(sql);
206  preparedStatement.setString(1, name);
207  resultSet = preparedStatement.executeQuery();
208  if (resultSet.next()) {
209  value = resultSet.getString("value");
210  }
211  } catch (SQLException ex) {
212  throw new CentralRepoException("Error getting value for name.", ex);
213  } finally {
214  CentralRepoDbUtil.closeStatement(preparedStatement);
215  CentralRepoDbUtil.closeResultSet(resultSet);
216  CentralRepoDbUtil.closeConnection(conn);
217  }
218 
219  return value;
220  }
221 
225  public final void clearCaches() {
226  synchronized (typeCache) {
227  typeCache.invalidateAll();
228  isCRTypeCacheInitialized = false;
229  }
230  caseCacheByUUID.invalidateAll();
231  caseCacheById.invalidateAll();
232  dataSourceCacheByDsObjectId.invalidateAll();
233  dataSourceCacheById.invalidateAll();
234  accountsCache.invalidateAll();
235  }
236 
245  @Override
246  public void updateDbInfo(String name, String value) throws CentralRepoException {
247  Connection conn = connect();
248 
249  PreparedStatement preparedStatement = null;
250  String sql = "UPDATE db_info SET value=? WHERE name=?";
251  try {
252  preparedStatement = conn.prepareStatement(sql);
253  preparedStatement.setString(1, value);
254  preparedStatement.setString(2, name);
255  preparedStatement.executeUpdate();
256  } catch (SQLException ex) {
257  throw new CentralRepoException("Error updating value for name.", ex);
258  } finally {
259  CentralRepoDbUtil.closeStatement(preparedStatement);
260  CentralRepoDbUtil.closeConnection(conn);
261  }
262  }
263 
273  @Override
274  public synchronized CorrelationCase newCase(CorrelationCase eamCase) throws CentralRepoException {
275 
276  if (eamCase.getCaseUUID() == null) {
277  throw new CentralRepoException("Case UUID is null");
278  }
279 
280  // check if there is already an existing CorrelationCase for this Case
281  CorrelationCase cRCase = getCaseByUUID(eamCase.getCaseUUID());
282  if (cRCase != null) {
283  return cRCase;
284  }
285 
286  Connection conn = connect();
287  PreparedStatement preparedStatement = null;
288 
289  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
290  + "examiner_name, examiner_email, examiner_phone, notes) "
291  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
292  + getConflictClause();
293  ResultSet resultSet = null;
294  try {
295  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
296 
297  preparedStatement.setString(1, eamCase.getCaseUUID());
298  if (null == eamCase.getOrg()) {
299  preparedStatement.setNull(2, Types.INTEGER);
300  } else {
301  preparedStatement.setInt(2, eamCase.getOrg().getOrgID());
302  }
303  preparedStatement.setString(3, eamCase.getDisplayName());
304  preparedStatement.setString(4, eamCase.getCreationDate());
305  if ("".equals(eamCase.getCaseNumber())) {
306  preparedStatement.setNull(5, Types.INTEGER);
307  } else {
308  preparedStatement.setString(5, eamCase.getCaseNumber());
309  }
310  if ("".equals(eamCase.getExaminerName())) {
311  preparedStatement.setNull(6, Types.INTEGER);
312  } else {
313  preparedStatement.setString(6, eamCase.getExaminerName());
314  }
315  if ("".equals(eamCase.getExaminerEmail())) {
316  preparedStatement.setNull(7, Types.INTEGER);
317  } else {
318  preparedStatement.setString(7, eamCase.getExaminerEmail());
319  }
320  if ("".equals(eamCase.getExaminerPhone())) {
321  preparedStatement.setNull(8, Types.INTEGER);
322  } else {
323  preparedStatement.setString(8, eamCase.getExaminerPhone());
324  }
325  if ("".equals(eamCase.getNotes())) {
326  preparedStatement.setNull(9, Types.INTEGER);
327  } else {
328  preparedStatement.setString(9, eamCase.getNotes());
329  }
330 
331  preparedStatement.executeUpdate();
332  //update the case in the caches
333  resultSet = preparedStatement.getGeneratedKeys();
334  if (!resultSet.next()) {
335  throw new CentralRepoException(String.format("Failed to INSERT case %s in central repo", eamCase.getCaseUUID()));
336  }
337  int caseID = resultSet.getInt(1); //last_insert_rowid()
338  CorrelationCase correlationCase = new CorrelationCase(caseID, eamCase.getCaseUUID(), eamCase.getOrg(),
339  eamCase.getDisplayName(), eamCase.getCreationDate(), eamCase.getCaseNumber(), eamCase.getExaminerName(),
340  eamCase.getExaminerEmail(), eamCase.getExaminerPhone(), eamCase.getNotes());
341  caseCacheByUUID.put(eamCase.getCaseUUID(), correlationCase);
342  caseCacheById.put(caseID, correlationCase);
343  } catch (SQLException ex) {
344  throw new CentralRepoException("Error inserting new case.", ex); // NON-NLS
345  } finally {
346  CentralRepoDbUtil.closeResultSet(resultSet);
347  CentralRepoDbUtil.closeStatement(preparedStatement);
348  CentralRepoDbUtil.closeConnection(conn);
349  }
350 
351  // get a new version with the updated ID
352  return getCaseByUUID(eamCase.getCaseUUID());
353  }
354 
360  @Override
361  public CorrelationCase newCase(Case autopsyCase) throws CentralRepoException {
362  if (autopsyCase == null) {
363  throw new CentralRepoException("Case is null");
364  }
365 
366  CorrelationCase curCeCase = new CorrelationCase(
367  -1,
368  autopsyCase.getName(), // unique case ID
369  CentralRepoOrganization.getDefault(),
370  autopsyCase.getDisplayName(),
371  autopsyCase.getCreatedDate(),
372  autopsyCase.getNumber(),
373  autopsyCase.getExaminer(),
374  autopsyCase.getExaminerEmail(),
375  autopsyCase.getExaminerPhone(),
376  autopsyCase.getCaseNotes());
377  return newCase(curCeCase);
378  }
379 
380  @Override
381  public CorrelationCase getCase(Case autopsyCase) throws CentralRepoException {
382  return getCaseByUUID(autopsyCase.getName());
383  }
384 
390  @Override
391  public void updateCase(CorrelationCase eamCase) throws CentralRepoException {
392  if (eamCase == null) {
393  throw new CentralRepoException("Correlation case is null");
394  }
395 
396  Connection conn = connect();
397 
398  PreparedStatement preparedStatement = null;
399  String sql = "UPDATE cases "
400  + "SET org_id=?, case_name=?, creation_date=?, case_number=?, examiner_name=?, examiner_email=?, examiner_phone=?, notes=? "
401  + "WHERE case_uid=?";
402 
403  try {
404  preparedStatement = conn.prepareStatement(sql);
405 
406  if (null == eamCase.getOrg()) {
407  preparedStatement.setNull(1, Types.INTEGER);
408  } else {
409  preparedStatement.setInt(1, eamCase.getOrg().getOrgID());
410  }
411  preparedStatement.setString(2, eamCase.getDisplayName());
412  preparedStatement.setString(3, eamCase.getCreationDate());
413 
414  if ("".equals(eamCase.getCaseNumber())) {
415  preparedStatement.setNull(4, Types.INTEGER);
416  } else {
417  preparedStatement.setString(4, eamCase.getCaseNumber());
418  }
419  if ("".equals(eamCase.getExaminerName())) {
420  preparedStatement.setNull(5, Types.INTEGER);
421  } else {
422  preparedStatement.setString(5, eamCase.getExaminerName());
423  }
424  if ("".equals(eamCase.getExaminerEmail())) {
425  preparedStatement.setNull(6, Types.INTEGER);
426  } else {
427  preparedStatement.setString(6, eamCase.getExaminerEmail());
428  }
429  if ("".equals(eamCase.getExaminerPhone())) {
430  preparedStatement.setNull(7, Types.INTEGER);
431  } else {
432  preparedStatement.setString(7, eamCase.getExaminerPhone());
433  }
434  if ("".equals(eamCase.getNotes())) {
435  preparedStatement.setNull(8, Types.INTEGER);
436  } else {
437  preparedStatement.setString(8, eamCase.getNotes());
438  }
439 
440  preparedStatement.setString(9, eamCase.getCaseUUID());
441 
442  preparedStatement.executeUpdate();
443  //update the case in the cache
444  caseCacheById.put(eamCase.getID(), eamCase);
445  caseCacheByUUID.put(eamCase.getCaseUUID(), eamCase);
446  } catch (SQLException ex) {
447  throw new CentralRepoException("Error updating case.", ex); // NON-NLS
448  } finally {
449  CentralRepoDbUtil.closeStatement(preparedStatement);
450  CentralRepoDbUtil.closeConnection(conn);
451  }
452  }
453 
461  @Override
462  public CorrelationCase getCaseByUUID(String caseUUID) throws CentralRepoException {
463  try {
464  return caseCacheByUUID.get(caseUUID, () -> getCaseByUUIDFromCr(caseUUID));
465  } catch (CacheLoader.InvalidCacheLoadException ignored) {
466  //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
467  return null;
468  } catch (ExecutionException ex) {
469  throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
470  }
471  }
472 
480  private CorrelationCase getCaseByUUIDFromCr(String caseUUID) throws CentralRepoException {
481  Connection conn = connect();
482 
483  CorrelationCase eamCaseResult = null;
484  PreparedStatement preparedStatement = null;
485  ResultSet resultSet = null;
486 
487  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
488  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
489  + "FROM cases "
490  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
491  + "WHERE case_uid=?";
492 
493  try {
494  preparedStatement = conn.prepareStatement(sql);
495  preparedStatement.setString(1, caseUUID);
496  resultSet = preparedStatement.executeQuery();
497  if (resultSet.next()) {
498  eamCaseResult = getEamCaseFromResultSet(resultSet);
499  }
500  if (eamCaseResult != null) {
501  //Update the version in the other cache
502  caseCacheById.put(eamCaseResult.getID(), eamCaseResult);
503  }
504  } catch (SQLException ex) {
505  throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
506  } finally {
507  CentralRepoDbUtil.closeStatement(preparedStatement);
508  CentralRepoDbUtil.closeResultSet(resultSet);
509  CentralRepoDbUtil.closeConnection(conn);
510  }
511 
512  return eamCaseResult;
513  }
514 
522  @Override
523  public CorrelationCase getCaseById(int caseId) throws CentralRepoException {
524  try {
525  return caseCacheById.get(caseId, () -> getCaseByIdFromCr(caseId));
526  } catch (CacheLoader.InvalidCacheLoadException ignored) {
527  //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
528  return null;
529  } catch (ExecutionException ex) {
530  throw new CentralRepoException("Error getting autopsy case from Central repo", ex);
531  }
532  }
533 
541  private CorrelationCase getCaseByIdFromCr(int caseId) throws CentralRepoException {
542  Connection conn = connect();
543 
544  CorrelationCase eamCaseResult = null;
545  PreparedStatement preparedStatement = null;
546  ResultSet resultSet = null;
547 
548  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
549  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
550  + "FROM cases "
551  + "LEFT JOIN organizations ON cases.org_id=organizations.id "
552  + "WHERE cases.id=?";
553  try {
554  preparedStatement = conn.prepareStatement(sql);
555  preparedStatement.setInt(1, caseId);
556  resultSet = preparedStatement.executeQuery();
557  if (resultSet.next()) {
558  eamCaseResult = getEamCaseFromResultSet(resultSet);
559  }
560  if (eamCaseResult != null) {
561  //Update the version in the other cache
562  caseCacheByUUID.put(eamCaseResult.getCaseUUID(), eamCaseResult);
563  }
564  } catch (SQLException ex) {
565  throw new CentralRepoException("Error getting case details.", ex); // NON-NLS
566  } finally {
567  CentralRepoDbUtil.closeStatement(preparedStatement);
568  CentralRepoDbUtil.closeResultSet(resultSet);
569  CentralRepoDbUtil.closeConnection(conn);
570  }
571 
572  return eamCaseResult;
573  }
574 
580  @Override
581  public List<CorrelationCase> getCases() throws CentralRepoException {
582  Connection conn = connect();
583 
584  List<CorrelationCase> cases = new ArrayList<>();
585  CorrelationCase eamCaseResult;
586  PreparedStatement preparedStatement = null;
587  ResultSet resultSet = null;
588 
589  String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
590  + "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
591  + "FROM cases "
592  + "LEFT JOIN organizations ON cases.org_id=organizations.id";
593 
594  try {
595  preparedStatement = conn.prepareStatement(sql);
596  resultSet = preparedStatement.executeQuery();
597  while (resultSet.next()) {
598  eamCaseResult = getEamCaseFromResultSet(resultSet);
599  cases.add(eamCaseResult);
600  }
601  } catch (SQLException ex) {
602  throw new CentralRepoException("Error getting all cases.", ex); // NON-NLS
603  } finally {
604  CentralRepoDbUtil.closeStatement(preparedStatement);
605  CentralRepoDbUtil.closeResultSet(resultSet);
606  CentralRepoDbUtil.closeConnection(conn);
607  }
608 
609  return cases;
610  }
611 
622  private static String getDataSourceByDSObjectIdCacheKey(int caseId, Long dataSourceObjectId) {
623  return "Case" + caseId + "DsObjectId" + dataSourceObjectId; //NON-NLS
624  }
625 
635  private static String getDataSourceByIdCacheKey(int caseId, int dataSourceId) {
636  return "Case" + caseId + "Id" + dataSourceId; //NON-NLS
637  }
638 
644  @Override
645  public CorrelationDataSource newDataSource(CorrelationDataSource eamDataSource) throws CentralRepoException {
646  if (eamDataSource.getCaseID() == -1) {
647  throw new CentralRepoException("Case ID is -1");
648  }
649  if (eamDataSource.getDeviceID() == null) {
650  throw new CentralRepoException("Device ID is null");
651  }
652  if (eamDataSource.getName() == null) {
653  throw new CentralRepoException("Name is null");
654  }
655  if (eamDataSource.getID() != -1) {
656  // This data source is already in the central repo
657  return eamDataSource;
658  }
659 
660  Connection conn = connect();
661 
662  PreparedStatement preparedStatement = null;
663  //The conflict clause exists in case multiple nodes are trying to add the data source because it did not exist at the same time
664  String sql = "INSERT INTO data_sources(device_id, case_id, name, datasource_obj_id, md5, sha1, sha256) VALUES (?, ?, ?, ?, ?, ?, ?) "
665  + getConflictClause();
666  ResultSet resultSet = null;
667  try {
668  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
669 
670  preparedStatement.setString(1, eamDataSource.getDeviceID());
671  preparedStatement.setInt(2, eamDataSource.getCaseID());
672  preparedStatement.setString(3, eamDataSource.getName());
673  preparedStatement.setLong(4, eamDataSource.getDataSourceObjectID());
674  preparedStatement.setString(5, eamDataSource.getMd5());
675  preparedStatement.setString(6, eamDataSource.getSha1());
676  preparedStatement.setString(7, eamDataSource.getSha256());
677 
678  preparedStatement.executeUpdate();
679  resultSet = preparedStatement.getGeneratedKeys();
680  if (!resultSet.next()) {
681  /*
682  * If nothing was inserted, then return the data source that
683  * exists in the Central Repository.
684  *
685  * This is expected to occur with PostgreSQL Central Repository
686  * databases.
687  */
688  try {
689  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
690  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
691  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
692  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
693  throw new CentralRepoException(String.format("Unable to to INSERT or get data source %s in central repo:", eamDataSource.getName()), getException);
694  }
695  } else {
696  //if a new data source was added to the central repository update the caches to include it and return it
697  int dataSourceId = resultSet.getInt(1); //last_insert_rowid()
698  CorrelationDataSource dataSource = new CorrelationDataSource(eamDataSource.getCaseID(), dataSourceId, eamDataSource.getDeviceID(), eamDataSource.getName(), eamDataSource.getDataSourceObjectID(), eamDataSource.getMd5(), eamDataSource.getSha1(), eamDataSource.getSha256());
699  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(dataSource.getCaseID(), dataSource.getDataSourceObjectID()), dataSource);
700  dataSourceCacheById.put(getDataSourceByIdCacheKey(dataSource.getCaseID(), dataSource.getID()), dataSource);
701  return dataSource;
702  }
703 
704  } catch (SQLException insertException) {
705  /*
706  * If an exception was thrown causing us to not return a new data
707  * source, attempt to get an existing data source with the same case
708  * ID and data source object ID.
709  *
710  * This exception block is expected to occur with SQLite Central
711  * Repository databases.
712  */
713  try {
714  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(
715  eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()),
716  () -> getDataSourceFromCr(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()));
717  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException getException) {
718  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);
719  }
720  } finally {
721  CentralRepoDbUtil.closeResultSet(resultSet);
722  CentralRepoDbUtil.closeStatement(preparedStatement);
723  CentralRepoDbUtil.closeConnection(conn);
724  }
725  }
726 
738  @Override
739  public CorrelationDataSource getDataSource(CorrelationCase correlationCase, Long dataSourceObjectId) throws CentralRepoException {
740 
741  if (correlationCase == null) {
742  throw new CentralRepoException("Correlation case is null");
743  }
744  try {
745  return dataSourceCacheByDsObjectId.get(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), dataSourceObjectId), () -> getDataSourceFromCr(correlationCase.getID(), dataSourceObjectId));
746  } catch (CacheLoader.InvalidCacheLoadException ignored) {
747  //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
748  return null;
749  } catch (ExecutionException ex) {
750  throw new CentralRepoException("Error getting data source from central repository", ex);
751  }
752  }
753 
766  private CorrelationDataSource getDataSourceFromCr(int correlationCaseId, Long dataSourceObjectId) throws CentralRepoException {
767  Connection conn = connect();
768 
769  CorrelationDataSource eamDataSourceResult = null;
770  PreparedStatement preparedStatement = null;
771  ResultSet resultSet = null;
772 
773  String sql = "SELECT * FROM data_sources WHERE datasource_obj_id=? AND case_id=?"; // NON-NLS
774 
775  try {
776  preparedStatement = conn.prepareStatement(sql);
777  preparedStatement.setLong(1, dataSourceObjectId);
778  preparedStatement.setInt(2, correlationCaseId);
779  resultSet = preparedStatement.executeQuery();
780  if (resultSet.next()) {
781  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
782  }
783  if (eamDataSourceResult != null) {
784  dataSourceCacheById.put(getDataSourceByIdCacheKey(correlationCaseId, eamDataSourceResult.getID()), eamDataSourceResult);
785  }
786  } catch (SQLException ex) {
787  throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
788  } finally {
789  CentralRepoDbUtil.closeStatement(preparedStatement);
790  CentralRepoDbUtil.closeResultSet(resultSet);
791  CentralRepoDbUtil.closeConnection(conn);
792  }
793 
794  return eamDataSourceResult;
795  }
796 
806  @Override
807  public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
808  if (correlationCase == null) {
809  throw new CentralRepoException("Correlation case is null");
810  }
811  try {
812  return dataSourceCacheById.get(getDataSourceByIdCacheKey(correlationCase.getID(), dataSourceId), () -> getDataSourceByIdFromCr(correlationCase, dataSourceId));
813  } catch (CacheLoader.InvalidCacheLoadException ignored) {
814  //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
815  return null;
816  } catch (ExecutionException ex) {
817  throw new CentralRepoException("Error getting data source from central repository", ex);
818  }
819  }
820 
830  private CorrelationDataSource getDataSourceByIdFromCr(CorrelationCase correlationCase, int dataSourceId) throws CentralRepoException {
831  Connection conn = connect();
832 
833  CorrelationDataSource eamDataSourceResult = null;
834  PreparedStatement preparedStatement = null;
835  ResultSet resultSet = null;
836 
837  String sql = "SELECT * FROM data_sources WHERE id=? AND case_id=?"; // NON-NLS
838 
839  try {
840  preparedStatement = conn.prepareStatement(sql);
841  preparedStatement.setInt(1, dataSourceId);
842  preparedStatement.setInt(2, correlationCase.getID());
843  resultSet = preparedStatement.executeQuery();
844  if (resultSet.next()) {
845  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
846  }
847  if (eamDataSourceResult != null) {
848  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(correlationCase.getID(), eamDataSourceResult.getDataSourceObjectID()), eamDataSourceResult);
849  }
850  } catch (SQLException ex) {
851  throw new CentralRepoException("Error getting data source.", ex); // NON-NLS
852  } finally {
853  CentralRepoDbUtil.closeStatement(preparedStatement);
854  CentralRepoDbUtil.closeResultSet(resultSet);
855  CentralRepoDbUtil.closeConnection(conn);
856  }
857 
858  return eamDataSourceResult;
859  }
860 
866  @Override
867  public List<CorrelationDataSource> getDataSources() throws CentralRepoException {
868  Connection conn = connect();
869 
870  List<CorrelationDataSource> dataSources = new ArrayList<>();
871  CorrelationDataSource eamDataSourceResult;
872  PreparedStatement preparedStatement = null;
873  ResultSet resultSet = null;
874 
875  String sql = "SELECT * FROM data_sources";
876 
877  try {
878  preparedStatement = conn.prepareStatement(sql);
879  resultSet = preparedStatement.executeQuery();
880  while (resultSet.next()) {
881  eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
882  dataSources.add(eamDataSourceResult);
883  }
884  } catch (SQLException ex) {
885  throw new CentralRepoException("Error getting all data sources.", ex); // NON-NLS
886  } finally {
887  CentralRepoDbUtil.closeStatement(preparedStatement);
888  CentralRepoDbUtil.closeResultSet(resultSet);
889  CentralRepoDbUtil.closeConnection(conn);
890  }
891 
892  return dataSources;
893  }
894 
900  @Override
901  public void updateDataSourceMd5Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
902  updateDataSourceStringValue(eamDataSource, "md5", eamDataSource.getMd5());
903  }
904 
910  @Override
911  public void updateDataSourceSha1Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
912  updateDataSourceStringValue(eamDataSource, "sha1", eamDataSource.getSha1());
913  }
914 
921  @Override
922  public void updateDataSourceSha256Hash(CorrelationDataSource eamDataSource) throws CentralRepoException {
923  updateDataSourceStringValue(eamDataSource, "sha256", eamDataSource.getSha256());
924  }
925 
933  private void updateDataSourceStringValue(CorrelationDataSource eamDataSource, String column, String value) throws CentralRepoException {
934  if (eamDataSource == null) {
935  throw new CentralRepoException("Correlation data source is null");
936  }
937 
938  Connection conn = connect();
939 
940  PreparedStatement preparedStatement = null;
941  String sql = "UPDATE data_sources "
942  + "SET " + column + "=? "
943  + "WHERE id=?";
944 
945  try {
946  preparedStatement = conn.prepareStatement(sql);
947 
948  preparedStatement.setString(1, value);
949  preparedStatement.setInt(2, eamDataSource.getID());
950 
951  preparedStatement.executeUpdate();
952  //update the case in the cache
953  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getDataSourceObjectID()), eamDataSource);
954  dataSourceCacheById.put(getDataSourceByIdCacheKey(eamDataSource.getCaseID(), eamDataSource.getID()), eamDataSource);
955  } catch (SQLException ex) {
956  throw new CentralRepoException(String.format("Error updating data source (obj_id=%d).", eamDataSource.getDataSourceObjectID()), ex); // NON-NLS
957  } finally {
958  CentralRepoDbUtil.closeStatement(preparedStatement);
959  CentralRepoDbUtil.closeConnection(conn);
960  }
961  }
962 
971  @Override
972  public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws CentralRepoException {
973 
974  Connection conn = connect();
975 
976  PreparedStatement preparedStatement = null;
977 
978  String sql = "UPDATE data_sources SET name = ? WHERE id = ?";
979 
980  try {
981  preparedStatement = conn.prepareStatement(sql);
982  preparedStatement.setString(1, newName);
983  preparedStatement.setInt(2, eamDataSource.getID());
984  preparedStatement.executeUpdate();
985 
986  CorrelationDataSource updatedDataSource = new CorrelationDataSource(
987  eamDataSource.getCaseID(),
988  eamDataSource.getID(),
989  eamDataSource.getDeviceID(),
990  newName,
991  eamDataSource.getDataSourceObjectID(),
992  eamDataSource.getMd5(),
993  eamDataSource.getSha1(),
994  eamDataSource.getSha256());
995 
996  dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getDataSourceObjectID()), updatedDataSource);
997  dataSourceCacheById.put(getDataSourceByIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getID()), updatedDataSource);
998  } catch (SQLException ex) {
999  throw new CentralRepoException("Error updating name of data source with ID " + eamDataSource.getDataSourceObjectID()
1000  + " to " + newName, ex); // NON-NLS
1001  } finally {
1002  CentralRepoDbUtil.closeStatement(preparedStatement);
1003  CentralRepoDbUtil.closeConnection(conn);
1004  }
1005  }
1006 
1013  @Override
1014  public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1015  checkAddArtifactInstanceNulls(eamArtifact);
1016 
1017  // @@@ We should cache the case and data source IDs in memory
1018  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1019  boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
1020 
1021  String sql;
1022  // _instance table for accounts have an additional account_id column
1023  if (artifactHasAnAccount) {
1024  sql = "INSERT INTO "
1025  + tableName
1026  + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
1027  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
1028  + getConflictClause();
1029  } else {
1030  sql = "INSERT INTO "
1031  + tableName
1032  + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1033  + "VALUES (?, ?, ?, ?, ?, ?, ?) "
1034  + getConflictClause();
1035  }
1036 
1037  try (Connection conn = connect();
1038  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1039 
1040  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1041  preparedStatement.setInt(1, eamArtifact.getCorrelationCase().getID());
1042  preparedStatement.setInt(2, eamArtifact.getCorrelationDataSource().getID());
1043  preparedStatement.setString(3, eamArtifact.getCorrelationValue());
1044  preparedStatement.setString(4, eamArtifact.getFilePath().toLowerCase());
1045  preparedStatement.setByte(5, eamArtifact.getKnownStatus().getFileKnownValue());
1046 
1047  if ("".equals(eamArtifact.getComment())) {
1048  preparedStatement.setNull(6, Types.INTEGER);
1049  } else {
1050  preparedStatement.setString(6, eamArtifact.getComment());
1051  }
1052  preparedStatement.setLong(7, eamArtifact.getFileObjectId());
1053 
1054  // set in the accountId only for artifacts that represent accounts
1055  if (artifactHasAnAccount) {
1056  if (eamArtifact.getAccountId() >= 0) {
1057  preparedStatement.setLong(8, eamArtifact.getAccountId());
1058  } else {
1059  preparedStatement.setNull(8, Types.INTEGER);
1060  }
1061  }
1062 
1063  preparedStatement.executeUpdate();
1064  }
1065 
1066  } catch (SQLException ex) {
1067  throw new CentralRepoException("Error inserting new artifact into artifacts table.", ex); // NON-NLS
1068  }
1069  }
1070 
1083  @Override
1084  public CentralRepoAccount getOrCreateAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1085  // Get the account fom the accounts table
1086  String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1087 
1088  // insert the account. If there is a conflict, ignore it.
1089  String insertSQL;
1090  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
1091  case POSTGRESQL:
1092  insertSQL = "INSERT INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) " + getConflictClause(); //NON-NLS
1093  break;
1094  case SQLITE:
1095  insertSQL = "INSERT OR IGNORE INTO accounts (account_type_id, account_unique_identifier) VALUES (?, ?) "; //NON-NLS
1096  break;
1097  default:
1098  throw new CentralRepoException(String.format("Cannot add account to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
1099  }
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 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 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, crAccountType);
1170  return crAccountType;
1171  } else {
1172  throw new CentralRepoException("Failed to find entry for account type = " + accountTypeName);
1173  }
1174  }
1175  } catch (SQLException ex) {
1176  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
1177  }
1178  }
1179 
1197  @Override
1198  public CentralRepoAccount getAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws InvalidAccountIDException, CentralRepoException {
1199  String normalizedAccountID = CentralRepoAccount.normalizeAccountIdentifier(crAccountType, accountUniqueID);
1200  CentralRepoAccount crAccount = accountsCache.getIfPresent(Pair.of(crAccountType, normalizedAccountID));
1201  if (crAccount == null) {
1202  crAccount = getCRAccountFromDb(crAccountType, normalizedAccountID);
1203  if (crAccount != null) {
1204  accountsCache.put(Pair.of(crAccountType, normalizedAccountID), crAccount);
1205  }
1206  }
1207 
1208  return crAccount;
1209  }
1210 
1223  private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
1224 
1225  CentralRepoAccount account = null;
1226 
1227  String sql = "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?";
1228  try (Connection connection = connect();
1229  PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
1230 
1231  preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1232  preparedStatement.setString(2, accountUniqueID);
1233 
1234  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1235  if (resultSet.next()) {
1236  account = new CentralRepoAccount(resultSet.getInt("id"), crAccountType, resultSet.getString("account_unique_identifier")); //NON-NLS
1237  }
1238  }
1239  } catch (SQLException ex) {
1240  throw new CentralRepoException("Error getting account type id", ex);
1241  }
1242 
1243  return account;
1244  }
1245 
1246  private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1247  if (eamArtifact == null) {
1248  throw new CentralRepoException("CorrelationAttribute is null");
1249  }
1250  if (eamArtifact.getCorrelationType() == null) {
1251  throw new CentralRepoException("Correlation type is null");
1252  }
1253  if (eamArtifact.getCorrelationValue() == null) {
1254  throw new CentralRepoException("Correlation value is null");
1255  }
1256  if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
1257  throw new CentralRepoException("Artifact value too long for central repository."
1258  + "\nCorrelationArtifact ID: " + eamArtifact.getID()
1259  + "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1260  + "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1261 
1262  }
1263  if (eamArtifact.getCorrelationCase() == null) {
1264  throw new CentralRepoException("CorrelationAttributeInstance case is null");
1265  }
1266  if (eamArtifact.getCorrelationDataSource() == null) {
1267  throw new CentralRepoException("CorrelationAttributeInstance data source is null");
1268  }
1269  if (eamArtifact.getKnownStatus() == null) {
1270  throw new CentralRepoException("CorrelationAttributeInstance known status is null");
1271  }
1272  }
1273 
1274  @Override
1275  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1276  if (value == null) {
1277  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null value");
1278  }
1279  return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
1280  }
1281 
1282  @Override
1283  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) throws CentralRepoException, CorrelationAttributeNormalizationException {
1284  if (aType == null) {
1285  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1286  }
1287  if (values == null || values.isEmpty()) {
1288  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1289  }
1290  return getArtifactInstances(prepareGetInstancesSql(aType, values), aType);
1291  }
1292 
1293  @Override
1294  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) throws CentralRepoException, CorrelationAttributeNormalizationException {
1295  if (aType == null) {
1296  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1297  }
1298  if (values == null || values.isEmpty()) {
1299  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1300  }
1301  if (caseIds == null || caseIds.isEmpty()) {
1302  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified cases");
1303  }
1304  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1305  String sql
1306  = " and "
1307  + tableName
1308  + ".case_id in ('";
1309  StringBuilder inValuesBuilder = new StringBuilder(prepareGetInstancesSql(aType, values));
1310  inValuesBuilder.append(sql);
1311  inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '")));
1312  inValuesBuilder.append("')");
1313  return getArtifactInstances(inValuesBuilder.toString(), aType);
1314  }
1315 
1328  private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) throws CorrelationAttributeNormalizationException {
1329  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1330  String sql
1331  = "SELECT "
1332  + tableName
1333  + ".id as instance_id,"
1334  + tableName
1335  + ".value,"
1336  + tableName
1337  + ".file_obj_id,"
1338  + " 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 "
1339  + tableName
1340  + " LEFT JOIN cases ON "
1341  + tableName
1342  + ".case_id=cases.id"
1343  + " LEFT JOIN organizations ON cases.org_id=organizations.id"
1344  + " LEFT JOIN data_sources ON "
1345  + tableName
1346  + ".data_source_id=data_sources.id"
1347  + " WHERE value IN (";
1348  StringBuilder inValuesBuilder = new StringBuilder(sql);
1349  for (String value : values) {
1350  if (value != null) {
1351  inValuesBuilder.append("'");
1352  inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1353  inValuesBuilder.append("',");
1354  }
1355  }
1356  inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1357  inValuesBuilder.append(")");
1358  return inValuesBuilder.toString();
1359  }
1360 
1375  private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, CentralRepoException {
1376  Connection conn = connect();
1377  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1378  CorrelationAttributeInstance artifactInstance;
1379  PreparedStatement preparedStatement = null;
1380  ResultSet resultSet = null;
1381  try {
1382  preparedStatement = conn.prepareStatement(sql);
1383  resultSet = preparedStatement.executeQuery();
1384  while (resultSet.next()) {
1385  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1386  artifactInstances.add(artifactInstance);
1387  }
1388  } catch (SQLException ex) {
1389  throw new CentralRepoException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1390  } finally {
1391  CentralRepoDbUtil.closeStatement(preparedStatement);
1392  CentralRepoDbUtil.closeResultSet(resultSet);
1393  CentralRepoDbUtil.closeConnection(conn);
1394  }
1395  return artifactInstances;
1396  }
1397 
1408  @Override
1409  public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1410  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1411 
1412  Connection conn = connect();
1413 
1414  Long instanceCount = 0L;
1415  PreparedStatement preparedStatement = null;
1416  ResultSet resultSet = null;
1417 
1418  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1419  String sql
1420  = "SELECT count(*) FROM "
1421  + tableName
1422  + " WHERE value=?";
1423 
1424  try {
1425  preparedStatement = conn.prepareStatement(sql);
1426  preparedStatement.setString(1, normalizedValue);
1427  resultSet = preparedStatement.executeQuery();
1428  resultSet.next();
1429  instanceCount = resultSet.getLong(1);
1430  } catch (SQLException ex) {
1431  throw new CentralRepoException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1432  } finally {
1433  CentralRepoDbUtil.closeStatement(preparedStatement);
1434  CentralRepoDbUtil.closeResultSet(resultSet);
1435  CentralRepoDbUtil.closeConnection(conn);
1436  }
1437 
1438  return instanceCount;
1439  }
1440 
1441  @Override
1442  public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws CentralRepoException, CorrelationAttributeNormalizationException {
1443  if (corAttr == null) {
1444  throw new CentralRepoException("CorrelationAttribute is null");
1445  }
1446  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1447  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1448  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1449  return commonalityPercentage.intValue();
1450  }
1451 
1462  @Override
1463  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1464  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1465 
1466  Connection conn = connect();
1467 
1468  Long instanceCount = 0L;
1469  PreparedStatement preparedStatement = null;
1470  ResultSet resultSet = null;
1471 
1472  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1473  String sql
1474  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1475  + tableName
1476  + " WHERE value=?) AS "
1477  + tableName
1478  + "_distinct_case_data_source_tuple";
1479 
1480  try {
1481  preparedStatement = conn.prepareStatement(sql);
1482  preparedStatement.setString(1, normalizedValue);
1483  resultSet = preparedStatement.executeQuery();
1484  resultSet.next();
1485  instanceCount = resultSet.getLong(1);
1486  } catch (SQLException ex) {
1487  throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1488  } finally {
1489  CentralRepoDbUtil.closeStatement(preparedStatement);
1490  CentralRepoDbUtil.closeResultSet(resultSet);
1491  CentralRepoDbUtil.closeConnection(conn);
1492  }
1493 
1494  return instanceCount;
1495  }
1496 
1497  @Override
1498  public Long getCountUniqueDataSources() throws CentralRepoException {
1499  Connection conn = connect();
1500 
1501  Long instanceCount = 0L;
1502  PreparedStatement preparedStatement = null;
1503  ResultSet resultSet = null;
1504 
1505  String stmt = "SELECT count(*) FROM data_sources";
1506 
1507  try {
1508  preparedStatement = conn.prepareStatement(stmt);
1509  resultSet = preparedStatement.executeQuery();
1510  resultSet.next();
1511  instanceCount = resultSet.getLong(1);
1512  } catch (SQLException ex) {
1513  throw new CentralRepoException("Error counting data sources.", ex); // NON-NLS
1514  } finally {
1515  CentralRepoDbUtil.closeStatement(preparedStatement);
1516  CentralRepoDbUtil.closeResultSet(resultSet);
1517  CentralRepoDbUtil.closeConnection(conn);
1518  }
1519 
1520  return instanceCount;
1521  }
1522 
1534  @Override
1535  public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws CentralRepoException {
1536  Connection conn = connect();
1537 
1538  Long instanceCount = 0L;
1539  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1540  PreparedStatement preparedStatement = null;
1541  ResultSet resultSet = null;
1542 
1543  //Create query to get count of all instances in the database for the specified case specific data source
1544  String sql = "SELECT 0 ";
1545 
1546  for (CorrelationAttributeInstance.Type type : artifactTypes) {
1547  String table_name = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1548  sql
1549  += "+ (SELECT count(*) FROM "
1550  + table_name
1551  + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1552  }
1553  try {
1554  preparedStatement = conn.prepareStatement(sql);
1555 
1556  resultSet = preparedStatement.executeQuery();
1557  resultSet.next();
1558  instanceCount = resultSet.getLong(1);
1559  } catch (SQLException ex) {
1560  throw new CentralRepoException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1561  } finally {
1562  CentralRepoDbUtil.closeStatement(preparedStatement);
1563  CentralRepoDbUtil.closeResultSet(resultSet);
1564  CentralRepoDbUtil.closeConnection(conn);
1565  }
1566 
1567  return instanceCount;
1568  }
1569 
1577  @Override
1578  public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1579 
1580  if (eamArtifact.getCorrelationType() == null) {
1581  throw new CentralRepoException("Correlation type is null");
1582  }
1583 
1584  synchronized (bulkArtifacts) {
1585  if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
1586  bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
1587  }
1588  bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1589  bulkArtifactsCount++;
1590 
1591  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1592  commitAttributeInstancesBulk();
1593  }
1594  }
1595  }
1596 
1602  protected abstract String getConflictClause();
1603 
1608  @Override
1609  public void commitAttributeInstancesBulk() throws CentralRepoException {
1610  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1611 
1612  Connection conn = connect();
1613  PreparedStatement bulkPs = null;
1614 
1615  try {
1616  synchronized (bulkArtifacts) {
1617  if (bulkArtifactsCount == 0) {
1618  return;
1619  }
1620 
1621  for (String tableName : bulkArtifacts.keySet()) {
1622 
1623  String sql
1624  = "INSERT INTO "
1625  + tableName
1626  + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1627  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1628  + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1629  + getConflictClause();
1630 
1631  bulkPs = conn.prepareStatement(sql);
1632 
1633  Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1634  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1635 
1636  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1637 
1638  if (eamArtifact.getCorrelationCase() == null) {
1639  throw new CentralRepoException("CorrelationAttributeInstance case is null for: "
1640  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1641  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1642  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1643  }
1644  if (eamArtifact.getCorrelationDataSource() == null) {
1645  throw new CentralRepoException("CorrelationAttributeInstance data source is null for: "
1646  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1647  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1648  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1649  }
1650  if (eamArtifact.getKnownStatus() == null) {
1651  throw new CentralRepoException("CorrelationAttributeInstance known status is null for: "
1652  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1653  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1654  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1655  + "\n\tEam Instance: "
1656  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1657  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1658  }
1659 
1660  if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1661  bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1662  bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1663  bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1664  bulkPs.setString(4, eamArtifact.getCorrelationValue());
1665  bulkPs.setString(5, eamArtifact.getFilePath());
1666  bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1667  if ("".equals(eamArtifact.getComment())) {
1668  bulkPs.setNull(7, Types.INTEGER);
1669  } else {
1670  bulkPs.setString(7, eamArtifact.getComment());
1671  }
1672  bulkPs.setLong(8, eamArtifact.getFileObjectId());
1673  bulkPs.addBatch();
1674  } else {
1675  logger.log(Level.WARNING, ("Artifact value too long for central repository."
1676  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1677  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1678  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1679  + "\n\tEam Instance: "
1680  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1681  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1682  + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1683  }
1684  }
1685 
1686  }
1687 
1688  bulkPs.executeBatch();
1689  bulkArtifacts.get(tableName).clear();
1690  }
1691 
1692  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Bulk insert");
1693  HealthMonitor.submitTimingMetric(timingMetric);
1694 
1695  // Reset state
1696  bulkArtifactsCount = 0;
1697  }
1698  } catch (SQLException ex) {
1699  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
1700  } finally {
1701  CentralRepoDbUtil.closeStatement(bulkPs);
1702  CentralRepoDbUtil.closeConnection(conn);
1703  }
1704  }
1705 
1709  @Override
1710  public void bulkInsertCases(List<CorrelationCase> cases) throws CentralRepoException {
1711  if (cases == null) {
1712  throw new CentralRepoException("cases argument is null");
1713  }
1714 
1715  if (cases.isEmpty()) {
1716  return;
1717  }
1718 
1719  Connection conn = connect();
1720 
1721  int counter = 0;
1722  PreparedStatement bulkPs = null;
1723  try {
1724  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1725  + "examiner_name, examiner_email, examiner_phone, notes) "
1726  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1727  + getConflictClause();
1728  bulkPs = conn.prepareStatement(sql);
1729 
1730  for (CorrelationCase eamCase : cases) {
1731  bulkPs.setString(1, eamCase.getCaseUUID());
1732  if (null == eamCase.getOrg()) {
1733  bulkPs.setNull(2, Types.INTEGER);
1734  } else {
1735  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1736  }
1737  bulkPs.setString(3, eamCase.getDisplayName());
1738  bulkPs.setString(4, eamCase.getCreationDate());
1739 
1740  if ("".equals(eamCase.getCaseNumber())) {
1741  bulkPs.setNull(5, Types.INTEGER);
1742  } else {
1743  bulkPs.setString(5, eamCase.getCaseNumber());
1744  }
1745  if ("".equals(eamCase.getExaminerName())) {
1746  bulkPs.setNull(6, Types.INTEGER);
1747  } else {
1748  bulkPs.setString(6, eamCase.getExaminerName());
1749  }
1750  if ("".equals(eamCase.getExaminerEmail())) {
1751  bulkPs.setNull(7, Types.INTEGER);
1752  } else {
1753  bulkPs.setString(7, eamCase.getExaminerEmail());
1754  }
1755  if ("".equals(eamCase.getExaminerPhone())) {
1756  bulkPs.setNull(8, Types.INTEGER);
1757  } else {
1758  bulkPs.setString(8, eamCase.getExaminerPhone());
1759  }
1760  if ("".equals(eamCase.getNotes())) {
1761  bulkPs.setNull(9, Types.INTEGER);
1762  } else {
1763  bulkPs.setString(9, eamCase.getNotes());
1764  }
1765 
1766  bulkPs.addBatch();
1767 
1768  counter++;
1769 
1770  // limit a batch's max size to bulkArtifactsThreshold
1771  if (counter >= bulkArtifactsThreshold) {
1772  bulkPs.executeBatch();
1773  counter = 0;
1774  }
1775  }
1776  // send the remaining batch records
1777  bulkPs.executeBatch();
1778  } catch (SQLException ex) {
1779  throw new CentralRepoException("Error inserting bulk cases.", ex); // NON-NLS
1780  } finally {
1781  CentralRepoDbUtil.closeStatement(bulkPs);
1782  CentralRepoDbUtil.closeConnection(conn);
1783  }
1784  }
1785 
1795  @Override
1796  public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1797 
1798  if (eamArtifact == null) {
1799  throw new CentralRepoException("CorrelationAttributeInstance is null");
1800  }
1801  if (eamArtifact.getCorrelationCase() == null) {
1802  throw new CentralRepoException("Correlation case is null");
1803  }
1804  if (eamArtifact.getCorrelationDataSource() == null) {
1805  throw new CentralRepoException("Correlation data source is null");
1806  }
1807  Connection conn = connect();
1808  PreparedStatement preparedQuery = null;
1809  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1810  String sqlUpdate
1811  = "UPDATE "
1812  + tableName
1813  + " SET comment=? "
1814  + "WHERE case_id=? "
1815  + "AND data_source_id=? "
1816  + "AND value=? "
1817  + "AND file_path=?";
1818 
1819  try {
1820  preparedQuery = conn.prepareStatement(sqlUpdate);
1821  preparedQuery.setString(1, eamArtifact.getComment());
1822  preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1823  preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1824  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1825  preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1826  preparedQuery.executeUpdate();
1827  } catch (SQLException ex) {
1828  throw new CentralRepoException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1829  } finally {
1830  CentralRepoDbUtil.closeStatement(preparedQuery);
1831  CentralRepoDbUtil.closeConnection(conn);
1832  }
1833  }
1834 
1849  @Override
1850  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1851  CorrelationDataSource correlationDataSource, long objectID) throws CentralRepoException, CorrelationAttributeNormalizationException {
1852 
1853  if (correlationCase == null) {
1854  throw new CentralRepoException("Correlation case is null");
1855  }
1856 
1857  Connection conn = connect();
1858 
1859  PreparedStatement preparedStatement = null;
1860  ResultSet resultSet = null;
1861  CorrelationAttributeInstance correlationAttributeInstance = null;
1862 
1863  try {
1864 
1865  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1866  String sql
1867  = "SELECT id, value, file_path, known_status, comment FROM "
1868  + tableName
1869  + " WHERE case_id=?"
1870  + " AND file_obj_id=?";
1871 
1872  preparedStatement = conn.prepareStatement(sql);
1873  preparedStatement.setInt(1, correlationCase.getID());
1874  preparedStatement.setInt(2, (int) objectID);
1875  resultSet = preparedStatement.executeQuery();
1876  if (resultSet.next()) {
1877  int instanceId = resultSet.getInt(1);
1878  String value = resultSet.getString(2);
1879  String filePath = resultSet.getString(3);
1880  int knownStatus = resultSet.getInt(4);
1881  String comment = resultSet.getString(5);
1882 
1883  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1884  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1885  }
1886  } catch (SQLException ex) {
1887  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1888  } finally {
1889  CentralRepoDbUtil.closeStatement(preparedStatement);
1890  CentralRepoDbUtil.closeResultSet(resultSet);
1891  CentralRepoDbUtil.closeConnection(conn);
1892  }
1893 
1894  return correlationAttributeInstance;
1895  }
1896 
1911  @Override
1912  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1913  CorrelationDataSource correlationDataSource, String value, String filePath) throws CentralRepoException, CorrelationAttributeNormalizationException {
1914 
1915  if (correlationCase == null) {
1916  throw new CentralRepoException("Correlation case is null");
1917  }
1918  if (correlationDataSource == null) {
1919  throw new CentralRepoException("Correlation data source is null");
1920  }
1921  if (filePath == null) {
1922  throw new CentralRepoException("Correlation file path is null");
1923  }
1924 
1925  Connection conn = connect();
1926 
1927  PreparedStatement preparedStatement = null;
1928  ResultSet resultSet = null;
1929  CorrelationAttributeInstance correlationAttributeInstance = null;
1930 
1931  try {
1932  String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1933 
1934  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1935  String sql
1936  = "SELECT id, known_status, comment FROM "
1937  + tableName
1938  + " WHERE case_id=?"
1939  + " AND data_source_id=?"
1940  + " AND value=?"
1941  + " AND file_path=?";
1942 
1943  preparedStatement = conn.prepareStatement(sql);
1944  preparedStatement.setInt(1, correlationCase.getID());
1945  preparedStatement.setInt(2, correlationDataSource.getID());
1946  preparedStatement.setString(3, normalizedValue);
1947  preparedStatement.setString(4, filePath.toLowerCase());
1948  resultSet = preparedStatement.executeQuery();
1949  if (resultSet.next()) {
1950  int instanceId = resultSet.getInt(1);
1951  int knownStatus = resultSet.getInt(2);
1952  String comment = resultSet.getString(3);
1953  //null objectId used because we only fall back to using this method when objectID was not available
1954  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1955  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
1956  }
1957  } catch (SQLException ex) {
1958  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1959  } finally {
1960  CentralRepoDbUtil.closeStatement(preparedStatement);
1961  CentralRepoDbUtil.closeResultSet(resultSet);
1962  CentralRepoDbUtil.closeConnection(conn);
1963  }
1964 
1965  return correlationAttributeInstance;
1966  }
1967 
1978  @Override
1979  public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws CentralRepoException {
1980  if (eamArtifact == null) {
1981  throw new CentralRepoException("CorrelationAttribute is null");
1982  }
1983  if (knownStatus == null) {
1984  throw new CentralRepoException("Known status is null");
1985  }
1986 
1987  if (eamArtifact.getCorrelationCase() == null) {
1988  throw new CentralRepoException("Correlation case is null");
1989  }
1990  if (eamArtifact.getCorrelationDataSource() == null) {
1991  throw new CentralRepoException("Correlation data source is null");
1992  }
1993 
1994  Connection conn = connect();
1995 
1996  PreparedStatement preparedUpdate = null;
1997  PreparedStatement preparedQuery = null;
1998  ResultSet resultSet = null;
1999 
2000  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
2001 
2002  String sqlQuery
2003  = "SELECT id FROM "
2004  + tableName
2005  + " WHERE case_id=? "
2006  + "AND data_source_id=? "
2007  + "AND value=? "
2008  + "AND file_path=?";
2009 
2010  String sqlUpdate
2011  = "UPDATE "
2012  + tableName
2013  + " SET known_status=? WHERE id=?";
2014 
2015  try {
2016  preparedQuery = conn.prepareStatement(sqlQuery);
2017  preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
2018  preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
2019  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
2020  preparedQuery.setString(4, eamArtifact.getFilePath());
2021  resultSet = preparedQuery.executeQuery();
2022  if (resultSet.next()) {
2023  int instance_id = resultSet.getInt("id");
2024  preparedUpdate = conn.prepareStatement(sqlUpdate);
2025 
2026  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
2027  preparedUpdate.setInt(2, instance_id);
2028 
2029  preparedUpdate.executeUpdate();
2030  } else {
2031  // In this case, the user is tagging something that isn't in the database,
2032  // which means the case and/or datasource may also not be in the database.
2033  // We could improve effiency by keeping a list of all datasources and cases
2034  // in the database, but we don't expect the user to be tagging large numbers
2035  // of items (that didn't have the CE ingest module run on them) at once.
2036  CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
2037  if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
2038  newDataSource(eamArtifact.getCorrelationDataSource());
2039  }
2040  eamArtifact.setKnownStatus(knownStatus);
2041  addArtifactInstance(eamArtifact);
2042  }
2043 
2044  } catch (SQLException ex) {
2045  throw new CentralRepoException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
2046  } finally {
2047  CentralRepoDbUtil.closeStatement(preparedUpdate);
2048  CentralRepoDbUtil.closeStatement(preparedQuery);
2049  CentralRepoDbUtil.closeResultSet(resultSet);
2050  CentralRepoDbUtil.closeConnection(conn);
2051  }
2052  }
2053 
2062  @Override
2063  public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2064 
2065  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2066 
2067  Connection conn = connect();
2068 
2069  Long badInstances = 0L;
2070  PreparedStatement preparedStatement = null;
2071  ResultSet resultSet = null;
2072 
2073  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2074  String sql
2075  = "SELECT count(*) FROM "
2076  + tableName
2077  + " WHERE value=? AND known_status=?";
2078 
2079  try {
2080  preparedStatement = conn.prepareStatement(sql);
2081  preparedStatement.setString(1, normalizedValue);
2082  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2083  resultSet = preparedStatement.executeQuery();
2084  resultSet.next();
2085  badInstances = resultSet.getLong(1);
2086  } catch (SQLException ex) {
2087  throw new CentralRepoException("Error getting count of notable artifact instances.", ex); // NON-NLS
2088  } finally {
2089  CentralRepoDbUtil.closeStatement(preparedStatement);
2090  CentralRepoDbUtil.closeResultSet(resultSet);
2091  CentralRepoDbUtil.closeConnection(conn);
2092  }
2093 
2094  return badInstances;
2095  }
2096 
2109  @Override
2110  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2111 
2112  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2113 
2114  Connection conn = connect();
2115 
2116  Collection<String> caseNames = new LinkedHashSet<>();
2117 
2118  PreparedStatement preparedStatement = null;
2119  ResultSet resultSet = null;
2120 
2121  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2122  String sql
2123  = "SELECT DISTINCT case_name FROM "
2124  + tableName
2125  + " INNER JOIN cases ON "
2126  + tableName
2127  + ".case_id=cases.id WHERE "
2128  + tableName
2129  + ".value=? AND "
2130  + tableName
2131  + ".known_status=?";
2132 
2133  try {
2134  preparedStatement = conn.prepareStatement(sql);
2135  preparedStatement.setString(1, normalizedValue);
2136  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2137  resultSet = preparedStatement.executeQuery();
2138  while (resultSet.next()) {
2139  caseNames.add(resultSet.getString("case_name"));
2140  }
2141  } catch (SQLException ex) {
2142  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2143  } finally {
2144  CentralRepoDbUtil.closeStatement(preparedStatement);
2145  CentralRepoDbUtil.closeResultSet(resultSet);
2146  CentralRepoDbUtil.closeConnection(conn);
2147  }
2148 
2149  return caseNames.stream().collect(Collectors.toList());
2150  }
2151 
2164  @Override
2165  public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2166 
2167  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2168 
2169  Connection conn = connect();
2170 
2171  Collection<String> caseNames = new LinkedHashSet<>();
2172 
2173  PreparedStatement preparedStatement = null;
2174  ResultSet resultSet = null;
2175 
2176  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2177  String sql
2178  = "SELECT DISTINCT case_name FROM "
2179  + tableName
2180  + " INNER JOIN cases ON "
2181  + tableName
2182  + ".case_id=cases.id WHERE "
2183  + tableName
2184  + ".value=? ";
2185 
2186  try {
2187  preparedStatement = conn.prepareStatement(sql);
2188  preparedStatement.setString(1, normalizedValue);
2189  resultSet = preparedStatement.executeQuery();
2190  while (resultSet.next()) {
2191  caseNames.add(resultSet.getString("case_name"));
2192  }
2193  } catch (SQLException ex) {
2194  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2195  } finally {
2196  CentralRepoDbUtil.closeStatement(preparedStatement);
2197  CentralRepoDbUtil.closeResultSet(resultSet);
2198  CentralRepoDbUtil.closeConnection(conn);
2199  }
2200 
2201  return caseNames.stream().collect(Collectors.toList());
2202  }
2203 
2211  @Override
2212  public void deleteReferenceSet(int referenceSetID) throws CentralRepoException {
2213  deleteReferenceSetEntries(referenceSetID);
2214  deleteReferenceSetEntry(referenceSetID);
2215  }
2216 
2224  private void deleteReferenceSetEntry(int referenceSetID) throws CentralRepoException {
2225  Connection conn = connect();
2226 
2227  PreparedStatement preparedStatement = null;
2228  String sql = "DELETE FROM reference_sets WHERE id=?";
2229 
2230  try {
2231  preparedStatement = conn.prepareStatement(sql);
2232  preparedStatement.setInt(1, referenceSetID);
2233  preparedStatement.executeUpdate();
2234  } catch (SQLException ex) {
2235  throw new CentralRepoException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2236  } finally {
2237  CentralRepoDbUtil.closeStatement(preparedStatement);
2238  CentralRepoDbUtil.closeConnection(conn);
2239  }
2240  }
2241 
2250  private void deleteReferenceSetEntries(int referenceSetID) throws CentralRepoException {
2251  Connection conn = connect();
2252 
2253  PreparedStatement preparedStatement = null;
2254  String sql = "DELETE FROM %s WHERE reference_set_id=?";
2255 
2256  // When other reference types are added, this will need to loop over all the tables
2257  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2258 
2259  try {
2260  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2261  preparedStatement.setInt(1, referenceSetID);
2262  preparedStatement.executeUpdate();
2263  } catch (SQLException ex) {
2264  throw new CentralRepoException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2265  } finally {
2266  CentralRepoDbUtil.closeStatement(preparedStatement);
2267  CentralRepoDbUtil.closeConnection(conn);
2268  }
2269  }
2270 
2284  @Override
2285  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws CentralRepoException {
2286  CentralRepoFileSet refSet = this.getReferenceSetByID(referenceSetID);
2287  if (refSet == null) {
2288  return false;
2289  }
2290 
2291  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2292  }
2293 
2305  @Override
2306  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2307  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2308  }
2309 
2310  @Override
2311  public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2312  int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID;
2313  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash);
2314 
2315  Connection conn = connect();
2316 
2317  PreparedStatement preparedStatement = null;
2318  ResultSet resultSet = null;
2319  String sql = "SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?";
2320 
2321  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2322 
2323  try {
2324  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2325  preparedStatement.setString(1, normalizeValued);
2326  preparedStatement.setInt(2, referenceSetID);
2327  resultSet = preparedStatement.executeQuery();
2328  if (resultSet.next()) {
2329  String comment = resultSet.getString("comment");
2330  String hashFound = resultSet.getString("value");
2331  HashHitInfo found = new HashHitInfo(hashFound, "", "");
2332  found.addComment(comment);
2333  return found;
2334  } else {
2335  return null;
2336  }
2337  } catch (SQLException ex) {
2338  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2339  } finally {
2340  CentralRepoDbUtil.closeStatement(preparedStatement);
2341  CentralRepoDbUtil.closeResultSet(resultSet);
2342  CentralRepoDbUtil.closeConnection(conn);
2343  }
2344  }
2345 
2355  @Override
2356  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2357 
2358  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2359 
2360  Connection conn = connect();
2361 
2362  Long matchingInstances = 0L;
2363  PreparedStatement preparedStatement = null;
2364  ResultSet resultSet = null;
2365  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2366 
2367  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2368 
2369  try {
2370  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2371  preparedStatement.setString(1, normalizeValued);
2372  preparedStatement.setInt(2, referenceSetID);
2373  resultSet = preparedStatement.executeQuery();
2374  resultSet.next();
2375  matchingInstances = resultSet.getLong(1);
2376  } catch (SQLException ex) {
2377  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2378  } finally {
2379  CentralRepoDbUtil.closeStatement(preparedStatement);
2380  CentralRepoDbUtil.closeResultSet(resultSet);
2381  CentralRepoDbUtil.closeConnection(conn);
2382  }
2383 
2384  return 0 < matchingInstances;
2385  }
2386 
2395  @Override
2396  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2397 
2398  //this should be done here so that we can be certain that aType and value are valid before we proceed
2399  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2400 
2401  // TEMP: Only support file correlation type
2402  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2403  return false;
2404  }
2405 
2406  Connection conn = connect();
2407 
2408  Long badInstances = 0L;
2409  PreparedStatement preparedStatement = null;
2410  ResultSet resultSet = null;
2411  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2412 
2413  try {
2414  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
2415  preparedStatement.setString(1, normalizeValued);
2416  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2417  resultSet = preparedStatement.executeQuery();
2418  resultSet.next();
2419  badInstances = resultSet.getLong(1);
2420  } catch (SQLException ex) {
2421  throw new CentralRepoException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2422  } finally {
2423  CentralRepoDbUtil.closeStatement(preparedStatement);
2424  CentralRepoDbUtil.closeResultSet(resultSet);
2425  CentralRepoDbUtil.closeConnection(conn);
2426  }
2427 
2428  return 0 < badInstances;
2429  }
2430 
2439  @Override
2440  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2441  if (type == null) {
2442  throw new CentralRepoException("Correlation type is null");
2443  }
2444 
2445  if (instanceTableCallback == null) {
2446  throw new CentralRepoException("Callback interface is null");
2447  }
2448 
2449  Connection conn = connect();
2450  PreparedStatement preparedStatement = null;
2451  ResultSet resultSet = null;
2452  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2453  StringBuilder sql = new StringBuilder();
2454  sql.append("select * from ");
2455  sql.append(tableName);
2456 
2457  try {
2458  preparedStatement = conn.prepareStatement(sql.toString());
2459  resultSet = preparedStatement.executeQuery();
2460  instanceTableCallback.process(resultSet);
2461  } catch (SQLException ex) {
2462  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2463  } finally {
2464  CentralRepoDbUtil.closeStatement(preparedStatement);
2465  CentralRepoDbUtil.closeResultSet(resultSet);
2466  CentralRepoDbUtil.closeConnection(conn);
2467  }
2468  }
2469 
2479  @Override
2480  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2481  if (type == null) {
2482  throw new CentralRepoException("Correlation type is null");
2483  }
2484 
2485  if (instanceTableCallback == null) {
2486  throw new CentralRepoException("Callback interface is null");
2487  }
2488 
2489  if (whereClause == null) {
2490  throw new CentralRepoException("Where clause is null");
2491  }
2492 
2493  Connection conn = connect();
2494  PreparedStatement preparedStatement = null;
2495  ResultSet resultSet = null;
2496  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2497  StringBuilder sql = new StringBuilder(300);
2498  sql.append("select * from ")
2499  .append(tableName)
2500  .append(" WHERE ")
2501  .append(whereClause);
2502 
2503  try {
2504  preparedStatement = conn.prepareStatement(sql.toString());
2505  resultSet = preparedStatement.executeQuery();
2506  instanceTableCallback.process(resultSet);
2507  } catch (SQLException ex) {
2508  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2509  } finally {
2510  CentralRepoDbUtil.closeStatement(preparedStatement);
2511  CentralRepoDbUtil.closeResultSet(resultSet);
2512  CentralRepoDbUtil.closeConnection(conn);
2513  }
2514  }
2515 
2524  @Override
2525  public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2526 
2527  if (instanceTableCallback == null) {
2528  throw new CentralRepoException("Callback interface is null");
2529  }
2530 
2531  if (selectClause == null) {
2532  throw new CentralRepoException("Select clause is null");
2533  }
2534 
2535  Connection conn = connect();
2536  PreparedStatement preparedStatement = null;
2537  ResultSet resultSet = null;
2538  StringBuilder sql = new StringBuilder(300);
2539  sql.append("select ")
2540  .append(selectClause);
2541 
2542  try {
2543  preparedStatement = conn.prepareStatement(sql.toString());
2544  resultSet = preparedStatement.executeQuery();
2545  instanceTableCallback.process(resultSet);
2546  } catch (SQLException ex) {
2547  throw new CentralRepoException("Error running query", ex);
2548  } finally {
2549  CentralRepoDbUtil.closeStatement(preparedStatement);
2550  CentralRepoDbUtil.closeResultSet(resultSet);
2551  CentralRepoDbUtil.closeConnection(conn);
2552  }
2553  }
2554 
2555  @Override
2556  public void executeCommand(String sql, List<Object> params) throws CentralRepoException {
2557 
2558  try (Connection conn = connect();) {
2559 
2560  PreparedStatement preparedStatement = conn.prepareStatement(sql);
2561 
2562  // Fill in the params
2563  if (params != null) {
2564  int paramIndex = 1;
2565  for (Object param : params) {
2566  preparedStatement.setObject(paramIndex, param);
2567  paramIndex += 1;
2568  }
2569  }
2570  // execute the prepared statement
2571  preparedStatement.executeUpdate();
2572  } catch (SQLException ex) {
2573  throw new CentralRepoException(String.format("Error executing prepared statement for SQL %s", sql), ex);
2574  }
2575  }
2576 
2577  @Override
2578  public void executeQuery(String sql, List<Object> params, CentralRepositoryDbQueryCallback queryCallback) throws CentralRepoException {
2579  if (queryCallback == null) {
2580  throw new CentralRepoException("Query callback is null");
2581  }
2582 
2583 
2584  try ( Connection conn = connect();) {
2585  PreparedStatement preparedStatement = conn.prepareStatement(sql);
2586 
2587  // fill in the params
2588  if (params != null) {
2589  int paramIndex = 1;
2590  for (Object param : params) {
2591  preparedStatement.setObject(paramIndex, param);
2592  paramIndex += 1;
2593  }
2594  }
2595  // execute query, and the callback to process result
2596  try (ResultSet resultSet = preparedStatement.executeQuery();) {
2597  queryCallback.process(resultSet);
2598  }
2599  } catch (SQLException ex) {
2600  throw new CentralRepoException(String.format("Error executing prepared statement for SQL query %s", sql), ex);
2601  }
2602  }
2603 
2604  @Override
2605  public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) throws CentralRepoException {
2606  if (eamOrg == null) {
2607  throw new CentralRepoException("EamOrganization is null");
2608  } else if (eamOrg.getOrgID() != -1) {
2609  throw new CentralRepoException("EamOrganization already has an ID");
2610  }
2611 
2612  Connection conn = connect();
2613  ResultSet generatedKeys = null;
2614  PreparedStatement preparedStatement = null;
2615  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2616  + getConflictClause();
2617 
2618  try {
2619  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2620  preparedStatement.setString(1, eamOrg.getName());
2621  preparedStatement.setString(2, eamOrg.getPocName());
2622  preparedStatement.setString(3, eamOrg.getPocEmail());
2623  preparedStatement.setString(4, eamOrg.getPocPhone());
2624 
2625  preparedStatement.executeUpdate();
2626  generatedKeys = preparedStatement.getGeneratedKeys();
2627  if (generatedKeys.next()) {
2628  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2629  return eamOrg;
2630  } else {
2631  throw new SQLException("Creating user failed, no ID obtained.");
2632  }
2633  } catch (SQLException ex) {
2634  throw new CentralRepoException("Error inserting new organization.", ex); // NON-NLS
2635  } finally {
2636  CentralRepoDbUtil.closeStatement(preparedStatement);
2637  CentralRepoDbUtil.closeResultSet(generatedKeys);
2638  CentralRepoDbUtil.closeConnection(conn);
2639  }
2640  }
2641 
2649  @Override
2650  public List<CentralRepoOrganization> getOrganizations() throws CentralRepoException {
2651  Connection conn = connect();
2652 
2653  List<CentralRepoOrganization> orgs = new ArrayList<>();
2654  PreparedStatement preparedStatement = null;
2655  ResultSet resultSet = null;
2656  String sql = "SELECT * FROM organizations";
2657 
2658  try {
2659  preparedStatement = conn.prepareStatement(sql);
2660  resultSet = preparedStatement.executeQuery();
2661  while (resultSet.next()) {
2662  orgs.add(getEamOrganizationFromResultSet(resultSet));
2663  }
2664  return orgs;
2665 
2666  } catch (SQLException ex) {
2667  throw new CentralRepoException("Error getting all organizations.", ex); // NON-NLS
2668  } finally {
2669  CentralRepoDbUtil.closeStatement(preparedStatement);
2670  CentralRepoDbUtil.closeResultSet(resultSet);
2671  CentralRepoDbUtil.closeConnection(conn);
2672  }
2673  }
2674 
2684  @Override
2685  public CentralRepoOrganization getOrganizationByID(int orgID) throws CentralRepoException {
2686  Connection conn = connect();
2687 
2688  PreparedStatement preparedStatement = null;
2689  ResultSet resultSet = null;
2690  String sql = "SELECT * FROM organizations WHERE id=?";
2691 
2692  try {
2693  preparedStatement = conn.prepareStatement(sql);
2694  preparedStatement.setInt(1, orgID);
2695  resultSet = preparedStatement.executeQuery();
2696  resultSet.next();
2697  return getEamOrganizationFromResultSet(resultSet);
2698 
2699  } catch (SQLException ex) {
2700  throw new CentralRepoException("Error getting organization by id.", ex); // NON-NLS
2701  } finally {
2702  CentralRepoDbUtil.closeStatement(preparedStatement);
2703  CentralRepoDbUtil.closeResultSet(resultSet);
2704  CentralRepoDbUtil.closeConnection(conn);
2705  }
2706  }
2707 
2717  @Override
2718  public CentralRepoOrganization getReferenceSetOrganization(int referenceSetID) throws CentralRepoException {
2719 
2720  CentralRepoFileSet globalSet = getReferenceSetByID(referenceSetID);
2721  if (globalSet == null) {
2722  throw new CentralRepoException("Reference set with ID " + referenceSetID + " not found");
2723  }
2724  return (getOrganizationByID(globalSet.getOrgID()));
2725  }
2726 
2734  private void testArgument(CentralRepoOrganization org) throws CentralRepoException {
2735  if (org == null) {
2736  throw new CentralRepoException("EamOrganization is null");
2737  } else if (org.getOrgID() == -1) {
2738  throw new CentralRepoException("Organization has -1 row ID");
2739  }
2740  }
2741 
2753  @Override
2754  public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException {
2755 
2756  String querySQL = "SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "'";
2757  try (Connection connection = connect();
2758  Statement statement = connection.createStatement();
2759  ResultSet resultSet = statement.executeQuery(querySQL);) {
2760 
2761  if (resultSet.next()) {
2762  return new CentralRepoExaminer(resultSet.getLong("id"), resultSet.getString("login_name"));
2763  } else {
2764  // Could not find this user in the Examiner table, add a row for it.
2765  try {
2766  String insertSQL;
2767  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
2768  case POSTGRESQL:
2769  insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')" + getConflictClause(); //NON-NLS
2770  break;
2771  case SQLITE:
2772  insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')"; //NON-NLS
2773  break;
2774  default:
2775  throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
2776  }
2777  statement.execute(insertSQL);
2778 
2779  // Query the table again to get the row for the user
2780  try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
2781  if (resultSet2.next()) {
2782  return new CentralRepoExaminer(resultSet2.getLong("id"), resultSet2.getString("login_name"));
2783  } else {
2784  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName);
2785  }
2786  }
2787 
2788  } catch (SQLException ex) {
2789  throw new CentralRepoException("Error inserting row in examiners", ex);
2790  }
2791  }
2792 
2793  } catch (SQLException ex) {
2794  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex);
2795  }
2796  }
2797 
2806  @Override
2807  public void updateOrganization(CentralRepoOrganization updatedOrganization) throws CentralRepoException {
2808  testArgument(updatedOrganization);
2809 
2810  Connection conn = connect();
2811  PreparedStatement preparedStatement = null;
2812  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2813  try {
2814  preparedStatement = conn.prepareStatement(sql);
2815  preparedStatement.setString(1, updatedOrganization.getName());
2816  preparedStatement.setString(2, updatedOrganization.getPocName());
2817  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2818  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2819  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2820  preparedStatement.executeUpdate();
2821  } catch (SQLException ex) {
2822  throw new CentralRepoException("Error updating organization.", ex); // NON-NLS
2823  } finally {
2824  CentralRepoDbUtil.closeStatement(preparedStatement);
2825  CentralRepoDbUtil.closeConnection(conn);
2826  }
2827  }
2828 
2829  @Override
2830  public void deleteOrganization(CentralRepoOrganization organizationToDelete) throws CentralRepoException {
2831  testArgument(organizationToDelete);
2832 
2833  Connection conn = connect();
2834  PreparedStatement checkIfUsedStatement = null;
2835  ResultSet resultSet = null;
2836  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2837  PreparedStatement deleteOrgStatement = null;
2838  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2839  try {
2840  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2841  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2842  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2843  resultSet = checkIfUsedStatement.executeQuery();
2844  resultSet.next();
2845  if (resultSet.getLong(1) > 0) {
2846  throw new CentralRepoException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2847  }
2848  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2849  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2850  deleteOrgStatement.executeUpdate();
2851  } catch (SQLException ex) {
2852  throw new CentralRepoException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2853  } finally {
2854  CentralRepoDbUtil.closeStatement(checkIfUsedStatement);
2855  CentralRepoDbUtil.closeStatement(deleteOrgStatement);
2856  CentralRepoDbUtil.closeResultSet(resultSet);
2857  CentralRepoDbUtil.closeConnection(conn);
2858  }
2859  }
2860 
2870  @Override
2871  public int newReferenceSet(CentralRepoFileSet eamGlobalSet) throws CentralRepoException {
2872  if (eamGlobalSet == null) {
2873  throw new CentralRepoException("EamGlobalSet is null");
2874  }
2875 
2876  if (eamGlobalSet.getFileKnownStatus() == null) {
2877  throw new CentralRepoException("File known status on the EamGlobalSet is null");
2878  }
2879 
2880  if (eamGlobalSet.getType() == null) {
2881  throw new CentralRepoException("Type on the EamGlobalSet is null");
2882  }
2883 
2884  Connection conn = connect();
2885 
2886  PreparedStatement preparedStatement1 = null;
2887  PreparedStatement preparedStatement2 = null;
2888  ResultSet resultSet = null;
2889  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2890  + getConflictClause();
2891  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2892 
2893  try {
2894  preparedStatement1 = conn.prepareStatement(sql1);
2895  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2896  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2897  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2898  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2899  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2900  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2901  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2902 
2903  preparedStatement1.executeUpdate();
2904 
2905  preparedStatement2 = conn.prepareStatement(sql2);
2906  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2907  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2908  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2909  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2910 
2911  resultSet = preparedStatement2.executeQuery();
2912  resultSet.next();
2913  return resultSet.getInt("id");
2914 
2915  } catch (SQLException ex) {
2916  throw new CentralRepoException("Error inserting new global set.", ex); // NON-NLS
2917  } finally {
2918  CentralRepoDbUtil.closeStatement(preparedStatement1);
2919  CentralRepoDbUtil.closeStatement(preparedStatement2);
2920  CentralRepoDbUtil.closeResultSet(resultSet);
2921  CentralRepoDbUtil.closeConnection(conn);
2922  }
2923  }
2924 
2934  @Override
2935  public CentralRepoFileSet getReferenceSetByID(int referenceSetID) throws CentralRepoException {
2936  Connection conn = connect();
2937 
2938  PreparedStatement preparedStatement1 = null;
2939  ResultSet resultSet = null;
2940  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2941 
2942  try {
2943  preparedStatement1 = conn.prepareStatement(sql1);
2944  preparedStatement1.setInt(1, referenceSetID);
2945  resultSet = preparedStatement1.executeQuery();
2946  if (resultSet.next()) {
2947  return getEamGlobalSetFromResultSet(resultSet);
2948  } else {
2949  return null;
2950  }
2951 
2952  } catch (SQLException ex) {
2953  throw new CentralRepoException("Error getting reference set by id.", ex); // NON-NLS
2954  } finally {
2955  CentralRepoDbUtil.closeStatement(preparedStatement1);
2956  CentralRepoDbUtil.closeResultSet(resultSet);
2957  CentralRepoDbUtil.closeConnection(conn);
2958  }
2959  }
2960 
2970  @Override
2971  public List<CentralRepoFileSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
2972 
2973  if (correlationType == null) {
2974  throw new CentralRepoException("Correlation type is null");
2975  }
2976 
2977  List<CentralRepoFileSet> results = new ArrayList<>();
2978  Connection conn = connect();
2979 
2980  PreparedStatement preparedStatement1 = null;
2981  ResultSet resultSet = null;
2982  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
2983 
2984  try {
2985  preparedStatement1 = conn.prepareStatement(sql1);
2986  resultSet = preparedStatement1.executeQuery();
2987  while (resultSet.next()) {
2988  results.add(getEamGlobalSetFromResultSet(resultSet));
2989  }
2990 
2991  } catch (SQLException ex) {
2992  throw new CentralRepoException("Error getting reference sets.", ex); // NON-NLS
2993  } finally {
2994  CentralRepoDbUtil.closeStatement(preparedStatement1);
2995  CentralRepoDbUtil.closeResultSet(resultSet);
2996  CentralRepoDbUtil.closeConnection(conn);
2997  }
2998  return results;
2999  }
3000 
3010  @Override
3011  public void addReferenceInstance(CentralRepoFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3012  if (eamGlobalFileInstance.getKnownStatus() == null) {
3013  throw new CentralRepoException("Known status of EamGlobalFileInstance is null");
3014  }
3015  if (correlationType == null) {
3016  throw new CentralRepoException("Correlation type is null");
3017  }
3018 
3019  Connection conn = connect();
3020 
3021  PreparedStatement preparedStatement = null;
3022 
3023  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3024  + getConflictClause();
3025 
3026  try {
3027  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(correlationType)));
3028  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
3029  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
3030  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
3031  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
3032  preparedStatement.executeUpdate();
3033  } catch (SQLException ex) {
3034  throw new CentralRepoException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
3035  } finally {
3036  CentralRepoDbUtil.closeStatement(preparedStatement);
3037  CentralRepoDbUtil.closeConnection(conn);
3038  }
3039  }
3040 
3053  @Override
3054  public boolean referenceSetExists(String referenceSetName, String version) throws CentralRepoException {
3055  Connection conn = connect();
3056 
3057  PreparedStatement preparedStatement1 = null;
3058  ResultSet resultSet = null;
3059  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
3060 
3061  try {
3062  preparedStatement1 = conn.prepareStatement(sql1);
3063  preparedStatement1.setString(1, referenceSetName);
3064  preparedStatement1.setString(2, version);
3065  resultSet = preparedStatement1.executeQuery();
3066  return (resultSet.next());
3067 
3068  } catch (SQLException ex) {
3069  throw new CentralRepoException("Error testing whether reference set exists (name: " + referenceSetName
3070  + " version: " + version, ex); // NON-NLS
3071  } finally {
3072  CentralRepoDbUtil.closeStatement(preparedStatement1);
3073  CentralRepoDbUtil.closeResultSet(resultSet);
3074  CentralRepoDbUtil.closeConnection(conn);
3075  }
3076  }
3077 
3083  @Override
3084  public void bulkInsertReferenceTypeEntries(Set<CentralRepoFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws CentralRepoException {
3085  if (contentType == null) {
3086  throw new CentralRepoException("Correlation type is null");
3087  }
3088  if (globalInstances == null) {
3089  throw new CentralRepoException("Null set of EamGlobalFileInstance");
3090  }
3091 
3092  Connection conn = connect();
3093 
3094  PreparedStatement bulkPs = null;
3095  try {
3096  conn.setAutoCommit(false);
3097 
3098  // FUTURE: have a separate global_files table for each Type.
3099  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3100  + getConflictClause();
3101 
3102  bulkPs = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(contentType)));
3103 
3104  for (CentralRepoFileInstance globalInstance : globalInstances) {
3105  if (globalInstance.getKnownStatus() == null) {
3106  throw new CentralRepoException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
3107  }
3108 
3109  bulkPs.setInt(1, globalInstance.getGlobalSetID());
3110  bulkPs.setString(2, globalInstance.getMD5Hash());
3111  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
3112  bulkPs.setString(4, globalInstance.getComment());
3113  bulkPs.addBatch();
3114  }
3115 
3116  bulkPs.executeBatch();
3117  conn.commit();
3118  } catch (SQLException | CentralRepoException ex) {
3119  try {
3120  conn.rollback();
3121  } catch (SQLException ex2) {
3122  // We're alredy in an error state
3123  }
3124  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
3125  } finally {
3126  CentralRepoDbUtil.closeStatement(bulkPs);
3127  CentralRepoDbUtil.closeConnection(conn);
3128  }
3129  }
3130 
3141  @Override
3142  public List<CentralRepoFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws CentralRepoException, CorrelationAttributeNormalizationException {
3143  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
3144 
3145  Connection conn = connect();
3146 
3147  List<CentralRepoFileInstance> globalFileInstances = new ArrayList<>();
3148  PreparedStatement preparedStatement1 = null;
3149  ResultSet resultSet = null;
3150  String sql1 = "SELECT * FROM %s WHERE value=?";
3151 
3152  try {
3153  preparedStatement1 = conn.prepareStatement(String.format(sql1, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
3154  preparedStatement1.setString(1, normalizeValued);
3155  resultSet = preparedStatement1.executeQuery();
3156  while (resultSet.next()) {
3157  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
3158  }
3159 
3160  } catch (SQLException ex) {
3161  throw new CentralRepoException("Error getting reference instances by type and value.", ex); // NON-NLS
3162  } finally {
3163  CentralRepoDbUtil.closeStatement(preparedStatement1);
3164  CentralRepoDbUtil.closeResultSet(resultSet);
3165  CentralRepoDbUtil.closeConnection(conn);
3166  }
3167 
3168  return globalFileInstances;
3169  }
3170 
3180  @Override
3181  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3182  if (newType == null) {
3183  throw new CentralRepoException("Correlation type is null");
3184  }
3185  int typeId;
3186  if (-1 == newType.getId()) {
3187  typeId = newCorrelationTypeNotKnownId(newType);
3188  } else {
3189  typeId = newCorrelationTypeKnownId(newType);
3190  }
3191 
3192  synchronized (typeCache) {
3193  typeCache.put(newType.getId(), newType);
3194  }
3195  return typeId;
3196  }
3197 
3208  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3209  Connection conn = connect();
3210 
3211  PreparedStatement preparedStatement = null;
3212  PreparedStatement preparedStatementQuery = null;
3213  ResultSet resultSet = null;
3214  int typeId = 0;
3215  String insertSql;
3216  String querySql;
3217  // if we have a known ID, use it, if not (is -1) let the db assign it.
3218  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
3219 
3220  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3221 
3222  try {
3223  preparedStatement = conn.prepareStatement(insertSql);
3224 
3225  preparedStatement.setString(1, newType.getDisplayName());
3226  preparedStatement.setString(2, newType.getDbTableName());
3227  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
3228  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
3229 
3230  preparedStatement.executeUpdate();
3231 
3232  preparedStatementQuery = conn.prepareStatement(querySql);
3233  preparedStatementQuery.setString(1, newType.getDisplayName());
3234  preparedStatementQuery.setString(2, newType.getDbTableName());
3235 
3236  resultSet = preparedStatementQuery.executeQuery();
3237  if (resultSet.next()) {
3238  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3239  typeId = correlationType.getId();
3240  }
3241  } catch (SQLException ex) {
3242  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3243  } finally {
3244  CentralRepoDbUtil.closeStatement(preparedStatement);
3245  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3246  CentralRepoDbUtil.closeResultSet(resultSet);
3247  CentralRepoDbUtil.closeConnection(conn);
3248  }
3249  return typeId;
3250  }
3251 
3261  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3262  Connection conn = connect();
3263 
3264  PreparedStatement preparedStatement = null;
3265  PreparedStatement preparedStatementQuery = null;
3266  ResultSet resultSet = null;
3267  int typeId = 0;
3268  String insertSql;
3269  String querySql;
3270  // if we have a known ID, use it, if not (is -1) let the db assign it.
3271  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
3272 
3273  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3274 
3275  try {
3276  preparedStatement = conn.prepareStatement(insertSql);
3277 
3278  preparedStatement.setInt(1, newType.getId());
3279  preparedStatement.setString(2, newType.getDisplayName());
3280  preparedStatement.setString(3, newType.getDbTableName());
3281  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
3282  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
3283 
3284  preparedStatement.executeUpdate();
3285 
3286  preparedStatementQuery = conn.prepareStatement(querySql);
3287  preparedStatementQuery.setString(1, newType.getDisplayName());
3288  preparedStatementQuery.setString(2, newType.getDbTableName());
3289 
3290  resultSet = preparedStatementQuery.executeQuery();
3291  if (resultSet.next()) {
3292  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3293  typeId = correlationType.getId();
3294  }
3295  } catch (SQLException ex) {
3296  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3297  } finally {
3298  CentralRepoDbUtil.closeStatement(preparedStatement);
3299  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3300  CentralRepoDbUtil.closeResultSet(resultSet);
3301  CentralRepoDbUtil.closeConnection(conn);
3302  }
3303  return typeId;
3304  }
3305 
3306  @Override
3307  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws CentralRepoException {
3308 
3309  synchronized (typeCache) {
3310  if (isCRTypeCacheInitialized == false) {
3311  getCorrelationTypesFromCr();
3312  }
3313  return new ArrayList<>(typeCache.asMap().values());
3314  }
3315  }
3316 
3326  @Override
3327  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws CentralRepoException {
3328  Connection conn = connect();
3329 
3330  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3331  PreparedStatement preparedStatement = null;
3332  ResultSet resultSet = null;
3333  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
3334 
3335  try {
3336  preparedStatement = conn.prepareStatement(sql);
3337  resultSet = preparedStatement.executeQuery();
3338  while (resultSet.next()) {
3339  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3340  }
3341  return aTypes;
3342 
3343  } catch (SQLException ex) {
3344  throw new CentralRepoException("Error getting enabled correlation types.", ex); // NON-NLS
3345  } finally {
3346  CentralRepoDbUtil.closeStatement(preparedStatement);
3347  CentralRepoDbUtil.closeResultSet(resultSet);
3348  CentralRepoDbUtil.closeConnection(conn);
3349  }
3350  }
3351 
3361  @Override
3362  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws CentralRepoException {
3363  Connection conn = connect();
3364 
3365  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3366  PreparedStatement preparedStatement = null;
3367  ResultSet resultSet = null;
3368  String sql = "SELECT * FROM correlation_types WHERE supported=1";
3369 
3370  try {
3371  preparedStatement = conn.prepareStatement(sql);
3372  resultSet = preparedStatement.executeQuery();
3373  while (resultSet.next()) {
3374  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3375  }
3376  return aTypes;
3377 
3378  } catch (SQLException ex) {
3379  throw new CentralRepoException("Error getting supported correlation types.", ex); // NON-NLS
3380  } finally {
3381  CentralRepoDbUtil.closeStatement(preparedStatement);
3382  CentralRepoDbUtil.closeResultSet(resultSet);
3383  CentralRepoDbUtil.closeConnection(conn);
3384  }
3385  }
3386 
3394  @Override
3395  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws CentralRepoException {
3396  Connection conn = connect();
3397 
3398  PreparedStatement preparedStatement = null;
3399  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3400 
3401  try {
3402  preparedStatement = conn.prepareStatement(sql);
3403  preparedStatement.setString(1, aType.getDisplayName());
3404  preparedStatement.setString(2, aType.getDbTableName());
3405  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3406  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3407  preparedStatement.setInt(5, aType.getId());
3408  preparedStatement.executeUpdate();
3409  synchronized (typeCache) {
3410  typeCache.put(aType.getId(), aType);
3411  }
3412  } catch (SQLException ex) {
3413  throw new CentralRepoException("Error updating correlation type.", ex); // NON-NLS
3414  } finally {
3415  CentralRepoDbUtil.closeStatement(preparedStatement);
3416  CentralRepoDbUtil.closeConnection(conn);
3417  }
3418 
3419  }
3420 
3430  @Override
3431  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws CentralRepoException {
3432  try {
3433  synchronized (typeCache) {
3434  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3435  }
3436  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3437  //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
3438  return null;
3439  } catch (ExecutionException ex) {
3440  throw new CentralRepoException("Error getting correlation type", ex);
3441  }
3442  }
3443 
3453  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws CentralRepoException {
3454  Connection conn = connect();
3455 
3456  CorrelationAttributeInstance.Type aType;
3457  PreparedStatement preparedStatement = null;
3458  ResultSet resultSet = null;
3459  String sql = "SELECT * FROM correlation_types WHERE id=?";
3460 
3461  try {
3462  preparedStatement = conn.prepareStatement(sql);
3463  preparedStatement.setInt(1, typeId);
3464  resultSet = preparedStatement.executeQuery();
3465  if (resultSet.next()) {
3466  aType = getCorrelationTypeFromResultSet(resultSet);
3467  return aType;
3468  } else {
3469  throw new CentralRepoException("Failed to find entry for correlation type ID = " + typeId);
3470  }
3471 
3472  } catch (SQLException ex) {
3473  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
3474  } finally {
3475  CentralRepoDbUtil.closeStatement(preparedStatement);
3476  CentralRepoDbUtil.closeResultSet(resultSet);
3477  CentralRepoDbUtil.closeConnection(conn);
3478  }
3479  }
3480 
3487  private void getCorrelationTypesFromCr() throws CentralRepoException {
3488 
3489  // clear out the cache
3490  synchronized (typeCache) {
3491  typeCache.invalidateAll();
3492  isCRTypeCacheInitialized = false;
3493  }
3494 
3495  String sql = "SELECT * FROM correlation_types";
3496  try (Connection conn = connect();
3497  PreparedStatement preparedStatement = conn.prepareStatement(sql);
3498  ResultSet resultSet = preparedStatement.executeQuery();) {
3499 
3500  synchronized (typeCache) {
3501  while (resultSet.next()) {
3502  CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
3503  typeCache.put(aType.getId(), aType);
3504  }
3505  isCRTypeCacheInitialized = true;
3506  }
3507  } catch (SQLException ex) {
3508  throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS
3509  }
3510  }
3511 
3522  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3523  if (null == resultSet) {
3524  return null;
3525  }
3526 
3527  CentralRepoOrganization eamOrg = null;
3528 
3529  resultSet.getInt("org_id");
3530  if (!resultSet.wasNull()) {
3531 
3532  eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3533  resultSet.getString("org_name"),
3534  resultSet.getString("poc_name"),
3535  resultSet.getString("poc_email"),
3536  resultSet.getString("poc_phone"));
3537  }
3538 
3539  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3540  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3541  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3542 
3543  return eamCase;
3544  }
3545 
3546  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3547  if (null == resultSet) {
3548  return null;
3549  }
3550 
3551  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3552  resultSet.getInt("case_id"),
3553  resultSet.getInt("id"),
3554  resultSet.getString("device_id"),
3555  resultSet.getString("name"),
3556  resultSet.getLong("datasource_obj_id"),
3557  resultSet.getString("md5"),
3558  resultSet.getString("sha1"),
3559  resultSet.getString("sha256")
3560  );
3561 
3562  return eamDataSource;
3563  }
3564 
3565  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws CentralRepoException, SQLException {
3566  if (null == resultSet) {
3567  return null;
3568  }
3569 
3570  CorrelationAttributeInstance.Type eamArtifactType = new CorrelationAttributeInstance.Type(
3571  resultSet.getInt("id"),
3572  resultSet.getString("display_name"),
3573  resultSet.getString("db_table_name"),
3574  resultSet.getBoolean("supported"),
3575  resultSet.getBoolean("enabled")
3576  );
3577 
3578  return eamArtifactType;
3579  }
3580 
3591  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3592  if (null == resultSet) {
3593  return null;
3594  }
3595 
3596  CentralRepoOrganization eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3597  resultSet.getString("org_name"),
3598  resultSet.getString("poc_name"),
3599  resultSet.getString("poc_email"),
3600  resultSet.getString("poc_phone"));
3601 
3602  return new CorrelationAttributeInstance(
3603  aType,
3604  resultSet.getString("value"),
3605  resultSet.getInt("instance_id"),
3606  new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3607  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3608  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3609  new CorrelationDataSource(
3610  resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3611  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3612  resultSet.getString("file_path"),
3613  resultSet.getString("comment"),
3614  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3615  resultSet.getLong("file_obj_id"));
3616  }
3617 
3618  private CentralRepoOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3619  if (null == resultSet) {
3620  return null;
3621  }
3622 
3623  return new CentralRepoOrganization(
3624  resultSet.getInt("id"),
3625  resultSet.getString("org_name"),
3626  resultSet.getString("poc_name"),
3627  resultSet.getString("poc_email"),
3628  resultSet.getString("poc_phone")
3629  );
3630  }
3631 
3632  private CentralRepoFileSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException {
3633  if (null == resultSet) {
3634  return null;
3635  }
3636 
3637  return new CentralRepoFileSet(
3638  resultSet.getInt("id"),
3639  resultSet.getInt("org_id"),
3640  resultSet.getString("set_name"),
3641  resultSet.getString("version"),
3642  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3643  resultSet.getBoolean("read_only"),
3644  CentralRepository.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3645  LocalDate.parse(resultSet.getString("import_date"))
3646  );
3647  }
3648 
3649  private CentralRepoFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3650  if (null == resultSet) {
3651  return null;
3652  }
3653 
3654  return new CentralRepoFileInstance(
3655  resultSet.getInt("id"),
3656  resultSet.getInt("reference_set_id"),
3657  resultSet.getString("value"),
3658  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3659  resultSet.getString("comment")
3660  );
3661  }
3662 
3663  private String getPlatformSpecificInsertSQL(String sql) throws CentralRepoException {
3664 
3665  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
3666  case POSTGRESQL:
3667  return "INSERT " + sql + " ON CONFLICT DO NOTHING"; //NON-NLS
3668  case SQLITE:
3669  return "INSERT OR IGNORE " + sql;
3670 
3671  default:
3672  throw new CentralRepoException("Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
3673  }
3674  }
3675 
3686  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3687 
3693  @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.",
3694  "# {0} - minorVersion",
3695  "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
3696  "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
3697  "# {0} - majorVersion",
3698  "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
3699  "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
3700  "# {0} - platformName",
3701  "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
3702  @Override
3703  public void upgradeSchema() throws CentralRepoException, SQLException, IncompatibleCentralRepoException {
3704 
3705  ResultSet resultSet = null;
3706  Statement statement = null;
3707  PreparedStatement preparedStatement = null;
3708  Connection conn = null;
3709  CentralRepoPlatforms selectedPlatform = null;
3710  try {
3711 
3712  conn = connect(false);
3713  conn.setAutoCommit(false);
3714  statement = conn.createStatement();
3715  selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
3716  int minorVersion = 0;
3717  String minorVersionStr = null;
3718  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
3719  if (resultSet.next()) {
3720  minorVersionStr = resultSet.getString("value");
3721  try {
3722  minorVersion = Integer.parseInt(minorVersionStr);
3723  } catch (NumberFormatException ex) {
3724  throw new CentralRepoException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
3725  }
3726  } else {
3727  throw new CentralRepoException("Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
3728  }
3729 
3730  int majorVersion = 0;
3731  String majorVersionStr = null;
3732  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "'");
3733  if (resultSet.next()) {
3734  majorVersionStr = resultSet.getString("value");
3735  try {
3736  majorVersion = Integer.parseInt(majorVersionStr);
3737  } catch (NumberFormatException ex) {
3738  throw new CentralRepoException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
3739  }
3740  } else {
3741  throw new CentralRepoException("Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
3742  }
3743 
3744  /*
3745  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3746  * 4.10.0. The consequence of the bug is that the schema version
3747  * number is always reset to 1.0 or 1.1 if a Central Repository is
3748  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3749  * there is an effort in updates to 1.2 and greater to not retry
3750  * schema updates that may already have been done once.
3751  */
3752  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3753 
3754  //compare the major versions for compatability
3755  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3756  //because it is specific to case db schema versions only supporting major versions greater than 1
3757  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3758  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3759  }
3760  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3761  logger.log(Level.INFO, "Central Repository is up to date");
3762  return;
3763  }
3764  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3765  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3766  return;
3767  }
3768 
3769  /*
3770  * Update to 1.1
3771  */
3772  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3773  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3774  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3775  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3776 
3777  // There's an outide chance that the user has already made an organization with the default name,
3778  // and the default org being missing will not impact any database operations, so continue on
3779  // regardless of whether this succeeds.
3780  CentralRepoDbUtil.insertDefaultOrganization(conn);
3781  }
3782 
3783  /*
3784  * Update to 1.2
3785  */
3786  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3787  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3788 
3789  final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
3790  final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
3791  final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
3792  final String addValueIndexTemplate = RdbmsCentralRepoFactory.getAddValueIndexTemplate();
3793  final String addKnownStatusIndexTemplate = RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate();
3794  final String addObjectIdIndexTemplate = RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate();
3795 
3796  final String addAttributeSql;
3797  //get the data base specific code for creating a new _instance table
3798  switch (selectedPlatform) {
3799  case POSTGRESQL:
3800  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3801  break;
3802  case SQLITE:
3803  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3804  break;
3805  default:
3806  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3807  }
3808 
3809  final String dataSourcesTableName = "data_sources";
3810  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3811  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3812  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3813  }
3814  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3815  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3816  List<String> instaceTablesToAdd = new ArrayList<>();
3817  //update central repository to be able to store new correlation attributes
3818  final String wirelessNetworksDbTableName = "wireless_networks";
3819  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3820  final String macAddressDbTableName = "mac_address";
3821  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3822  final String imeiNumberDbTableName = "imei_number";
3823  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3824  final String iccidNumberDbTableName = "iccid_number";
3825  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3826  final String imsiNumberDbTableName = "imsi_number";
3827  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3828 
3829  //add the wireless_networks attribute to the correlation_types table
3830  preparedStatement = conn.prepareStatement(addAttributeSql);
3831  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3832  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3833  preparedStatement.setString(3, wirelessNetworksDbTableName);
3834  preparedStatement.setInt(4, 1);
3835  preparedStatement.setInt(5, 1);
3836  preparedStatement.execute();
3837 
3838  //add the mac_address attribute to the correlation_types table
3839  preparedStatement = conn.prepareStatement(addAttributeSql);
3840  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3841  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3842  preparedStatement.setString(3, macAddressDbTableName);
3843  preparedStatement.setInt(4, 1);
3844  preparedStatement.setInt(5, 1);
3845  preparedStatement.execute();
3846 
3847  //add the imei_number attribute to the correlation_types table
3848  preparedStatement = conn.prepareStatement(addAttributeSql);
3849  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3850  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3851  preparedStatement.setString(3, imeiNumberDbTableName);
3852  preparedStatement.setInt(4, 1);
3853  preparedStatement.setInt(5, 1);
3854  preparedStatement.execute();
3855 
3856  //add the imsi_number attribute to the correlation_types table
3857  preparedStatement = conn.prepareStatement(addAttributeSql);
3858  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3859  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3860  preparedStatement.setString(3, imsiNumberDbTableName);
3861  preparedStatement.setInt(4, 1);
3862  preparedStatement.setInt(5, 1);
3863  preparedStatement.execute();
3864 
3865  //add the iccid_number attribute to the correlation_types table
3866  preparedStatement = conn.prepareStatement(addAttributeSql);
3867  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3868  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3869  preparedStatement.setString(3, iccidNumberDbTableName);
3870  preparedStatement.setInt(4, 1);
3871  preparedStatement.setInt(5, 1);
3872  preparedStatement.execute();
3873 
3874  //create a new _instances tables and add indexes for their columns
3875  for (String tableName : instaceTablesToAdd) {
3876  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3877  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3878  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3879  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3880  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3881  }
3882 
3883  //add file_obj_id column to _instances table which do not already have it
3884  String instance_type_dbname;
3885  final String objectIdColumnName = "file_obj_id";
3886  for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
3887  instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
3888  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3889  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3890  }
3891  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3892  }
3893 
3894  /*
3895  * Add hash columns to the data_sources table.
3896  */
3897  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3898  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3899  }
3900  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3901  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3902  }
3903  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3904  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3905  }
3906 
3907  /*
3908  * Drop the db_info table and add it back in with the name
3909  * column having a UNIQUE constraint. The name column could now
3910  * be used as the primary key, but the essentially useless id
3911  * column is retained for the sake of backwards compatibility.
3912  * Note that the creation schema version number is set to 0.0 to
3913  * indicate that it is unknown.
3914  */
3915  String creationMajorVer;
3916  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3917  if (resultSet.next()) {
3918  creationMajorVer = resultSet.getString("value");
3919  } else {
3920  creationMajorVer = "0";
3921  }
3922  String creationMinorVer;
3923  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3924  if (resultSet.next()) {
3925  creationMinorVer = resultSet.getString("value");
3926  } else {
3927  creationMinorVer = "0";
3928  }
3929  statement.execute("DROP TABLE db_info");
3930  if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
3931  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3932  } else {
3933  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3934  }
3935  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3936  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3937  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3938  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3939  }
3940  /*
3941  * Update to 1.3
3942  */
3943  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3944  switch (selectedPlatform) {
3945  case POSTGRESQL:
3946  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3947  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3948  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
3949 
3950  break;
3951  case SQLITE:
3952  statement.execute("DROP INDEX IF EXISTS data_sources_name");
3953  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
3954  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
3955  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3956  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
3957  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
3958  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
3959  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
3960  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
3961  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesNameIndexStatement());
3962  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesObjectIdIndexStatement());
3963  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
3964  statement.execute("DROP TABLE old_data_sources");
3965  break;
3966  default:
3967  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3968  }
3969  }
3970 
3971  // Upgrade to 1.4
3972  (new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
3973 
3974  // Upgrade to 1.5
3975  (new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);
3976 
3977  updateSchemaVersion(conn);
3978  conn.commit();
3979  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
3980  } catch (SQLException | CentralRepoException ex) {
3981  try {
3982  if (conn != null) {
3983  conn.rollback();
3984  }
3985  } catch (SQLException ex2) {
3986  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
3987  }
3988  throw ex;
3989  } finally {
3990  CentralRepoDbUtil.closeResultSet(resultSet);
3991  CentralRepoDbUtil.closeStatement(preparedStatement);
3992  CentralRepoDbUtil.closeStatement(statement);
3993  CentralRepoDbUtil.closeConnection(conn);
3994  }
3995  }
3996 
3997 }
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
CentralRepoAccount getOrCreateAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)

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