Autopsy  4.15.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.lang.StringUtils;
45 import org.apache.commons.lang3.tuple.Pair;
46 import org.openide.util.NbBundle.Messages;
49 import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil.updateSchemaVersion;
53 import org.sleuthkit.datamodel.Account;
54 import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
55 import org.sleuthkit.datamodel.HashHitInfo;
56 import org.sleuthkit.datamodel.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 CentralRepoException {
1085  // Get the account fom the accounts table
1086  CentralRepoAccount account = getAccount(crAccountType, accountUniqueID);
1087 
1088  // account not found in the table, create it
1089  if (null == account) {
1090 
1091  String query = "INSERT INTO accounts (account_type_id, account_unique_identifier) "
1092  + "VALUES ( " + crAccountType.getAccountTypeId() + ", '"
1093  + accountUniqueID + "' )";
1094 
1095  try (Connection connection = connect();
1096  Statement s = connection.createStatement();) {
1097 
1098  s.execute(query);
1099  // get the account from the db - should exist now.
1100  account = getAccount(crAccountType, accountUniqueID);
1101  } catch (SQLException ex) {
1102  throw new CentralRepoException("Error adding an account to CR database.", ex);
1103  }
1104  }
1105 
1106  return account;
1107  }
1108 
1109  @Override
1110  public CentralRepoAccountType getAccountTypeByName(String accountTypeName) throws CentralRepoException {
1111  try {
1112  return accountTypesCache.get(accountTypeName, () -> getCRAccountTypeFromDb(accountTypeName));
1113  } catch (CacheLoader.InvalidCacheLoadException | ExecutionException ex) {
1114  throw new CentralRepoException("Error looking up CR account type in cache.", ex);
1115  }
1116  }
1117 
1118  @Override
1119  public Collection<CentralRepoAccountType> getAllAccountTypes() throws CentralRepoException {
1120 
1121  Collection<CentralRepoAccountType> accountTypes = new ArrayList<>();
1122 
1123  String sql = "SELECT * FROM account_types";
1124  try (Connection conn = connect();
1125  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1126 
1127  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1128  while (resultSet.next()) {
1129  Account.Type acctType = new Account.Type(resultSet.getString("type_name"), resultSet.getString("display_name"));
1130  CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1131 
1132  accountTypes.add(crAccountType);
1133  }
1134  }
1135  } catch (SQLException ex) {
1136  throw new CentralRepoException("Error getting account types from central repository.", ex); // NON-NLS
1137  }
1138  return accountTypes;
1139  }
1140 
1150  private CentralRepoAccountType getCRAccountTypeFromDb(String accountTypeName) throws CentralRepoException {
1151 
1152  String sql = "SELECT * FROM account_types WHERE type_name = ?";
1153  try (Connection conn = connect();
1154  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
1155 
1156  preparedStatement.setString(1, accountTypeName);
1157  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1158  if (resultSet.next()) {
1159  Account.Type acctType = new Account.Type(accountTypeName, resultSet.getString("display_name"));
1160  CentralRepoAccountType crAccountType = new CentralRepoAccountType(resultSet.getInt("id"), acctType, resultSet.getInt("correlation_type_id"));
1161  accountTypesCache.put(accountTypeName, crAccountType);
1162  return crAccountType;
1163  } else {
1164  throw new CentralRepoException("Failed to find entry for account type = " + accountTypeName);
1165  }
1166  }
1167  } catch (SQLException ex) {
1168  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
1169  }
1170  }
1171 
1188  private CentralRepoAccount getAccount(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
1189 
1190  CentralRepoAccount crAccount = accountsCache.getIfPresent(Pair.of(crAccountType, accountUniqueID));
1191  if (crAccount == null) {
1192  crAccount = getCRAccountFromDb(crAccountType, accountUniqueID);
1193  if (crAccount != null) {
1194  accountsCache.put(Pair.of(crAccountType, accountUniqueID), crAccount);
1195  }
1196  }
1197 
1198  return crAccount;
1199  }
1200 
1213  private CentralRepoAccount getCRAccountFromDb(CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException {
1214 
1215  CentralRepoAccount account = null;
1216 
1217  String sql = "SELECT * FROM accounts WHERE account_type_id = ? AND account_unique_identifier = ?";
1218  try (Connection connection = connect();
1219  PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
1220 
1221  preparedStatement.setInt(1, crAccountType.getAccountTypeId());
1222  preparedStatement.setString(2, accountUniqueID);
1223 
1224  try (ResultSet resultSet = preparedStatement.executeQuery();) {
1225  if (resultSet.next()) {
1226  account = new CentralRepoAccount(resultSet.getInt("id"), crAccountType, resultSet.getString("account_unique_identifier")); //NON-NLS
1227  }
1228  }
1229  } catch (SQLException ex) {
1230  throw new CentralRepoException("Error getting account type id", ex);
1231  }
1232 
1233  return account;
1234  }
1235 
1236  private void checkAddArtifactInstanceNulls(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1237  if (eamArtifact == null) {
1238  throw new CentralRepoException("CorrelationAttribute is null");
1239  }
1240  if (eamArtifact.getCorrelationType() == null) {
1241  throw new CentralRepoException("Correlation type is null");
1242  }
1243  if (eamArtifact.getCorrelationValue() == null) {
1244  throw new CentralRepoException("Correlation value is null");
1245  }
1246  if (eamArtifact.getCorrelationValue().length() >= MAX_VALUE_LENGTH) {
1247  throw new CentralRepoException("Artifact value too long for central repository."
1248  + "\nCorrelationArtifact ID: " + eamArtifact.getID()
1249  + "\nCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1250  + "\nCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1251 
1252  }
1253  if (eamArtifact.getCorrelationCase() == null) {
1254  throw new CentralRepoException("CorrelationAttributeInstance case is null");
1255  }
1256  if (eamArtifact.getCorrelationDataSource() == null) {
1257  throw new CentralRepoException("CorrelationAttributeInstance data source is null");
1258  }
1259  if (eamArtifact.getKnownStatus() == null) {
1260  throw new CentralRepoException("CorrelationAttributeInstance known status is null");
1261  }
1262  }
1263 
1264  @Override
1265  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1266  if (value == null) {
1267  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null value");
1268  }
1269  return getArtifactInstancesByTypeValues(aType, Arrays.asList(value));
1270  }
1271 
1272  @Override
1273  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValues(CorrelationAttributeInstance.Type aType, List<String> values) throws CentralRepoException, CorrelationAttributeNormalizationException {
1274  if (aType == null) {
1275  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1276  }
1277  if (values == null || values.isEmpty()) {
1278  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1279  }
1280  return getArtifactInstances(prepareGetInstancesSql(aType, values), aType);
1281  }
1282 
1283  @Override
1284  public List<CorrelationAttributeInstance> getArtifactInstancesByTypeValuesAndCases(CorrelationAttributeInstance.Type aType, List<String> values, List<Integer> caseIds) throws CentralRepoException, CorrelationAttributeNormalizationException {
1285  if (aType == null) {
1286  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances for null type");
1287  }
1288  if (values == null || values.isEmpty()) {
1289  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified values");
1290  }
1291  if (caseIds == null || caseIds.isEmpty()) {
1292  throw new CorrelationAttributeNormalizationException("Cannot get artifact instances without specified cases");
1293  }
1294  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1295  String sql
1296  = " and "
1297  + tableName
1298  + ".case_id in ('";
1299  StringBuilder inValuesBuilder = new StringBuilder(prepareGetInstancesSql(aType, values));
1300  inValuesBuilder.append(sql);
1301  inValuesBuilder.append(caseIds.stream().map(String::valueOf).collect(Collectors.joining("', '")));
1302  inValuesBuilder.append("')");
1303  return getArtifactInstances(inValuesBuilder.toString(), aType);
1304  }
1305 
1318  private String prepareGetInstancesSql(CorrelationAttributeInstance.Type aType, List<String> values) throws CorrelationAttributeNormalizationException {
1319  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1320  String sql
1321  = "SELECT "
1322  + tableName
1323  + ".id as instance_id,"
1324  + tableName
1325  + ".value,"
1326  + tableName
1327  + ".file_obj_id,"
1328  + " 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 "
1329  + tableName
1330  + " LEFT JOIN cases ON "
1331  + tableName
1332  + ".case_id=cases.id"
1333  + " LEFT JOIN organizations ON cases.org_id=organizations.id"
1334  + " LEFT JOIN data_sources ON "
1335  + tableName
1336  + ".data_source_id=data_sources.id"
1337  + " WHERE value IN (";
1338  StringBuilder inValuesBuilder = new StringBuilder(sql);
1339  for (String value : values) {
1340  if (value != null) {
1341  inValuesBuilder.append("'");
1342  inValuesBuilder.append(CorrelationAttributeNormalizer.normalize(aType, value));
1343  inValuesBuilder.append("',");
1344  }
1345  }
1346  inValuesBuilder.deleteCharAt(inValuesBuilder.length() - 1); //delete last comma
1347  inValuesBuilder.append(")");
1348  return inValuesBuilder.toString();
1349  }
1350 
1365  private List<CorrelationAttributeInstance> getArtifactInstances(String sql, CorrelationAttributeInstance.Type aType) throws CorrelationAttributeNormalizationException, CentralRepoException {
1366  Connection conn = connect();
1367  List<CorrelationAttributeInstance> artifactInstances = new ArrayList<>();
1368  CorrelationAttributeInstance artifactInstance;
1369  PreparedStatement preparedStatement = null;
1370  ResultSet resultSet = null;
1371  try {
1372  preparedStatement = conn.prepareStatement(sql);
1373  resultSet = preparedStatement.executeQuery();
1374  while (resultSet.next()) {
1375  artifactInstance = getEamArtifactInstanceFromResultSet(resultSet, aType);
1376  artifactInstances.add(artifactInstance);
1377  }
1378  } catch (SQLException ex) {
1379  throw new CentralRepoException("Error getting artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1380  } finally {
1381  CentralRepoDbUtil.closeStatement(preparedStatement);
1382  CentralRepoDbUtil.closeResultSet(resultSet);
1383  CentralRepoDbUtil.closeConnection(conn);
1384  }
1385  return artifactInstances;
1386  }
1387 
1398  @Override
1399  public Long getCountArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1400  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1401 
1402  Connection conn = connect();
1403 
1404  Long instanceCount = 0L;
1405  PreparedStatement preparedStatement = null;
1406  ResultSet resultSet = null;
1407 
1408  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1409  String sql
1410  = "SELECT count(*) FROM "
1411  + tableName
1412  + " WHERE value=?";
1413 
1414  try {
1415  preparedStatement = conn.prepareStatement(sql);
1416  preparedStatement.setString(1, normalizedValue);
1417  resultSet = preparedStatement.executeQuery();
1418  resultSet.next();
1419  instanceCount = resultSet.getLong(1);
1420  } catch (SQLException ex) {
1421  throw new CentralRepoException("Error getting count of artifact instances by artifactType and artifactValue.", ex); // NON-NLS
1422  } finally {
1423  CentralRepoDbUtil.closeStatement(preparedStatement);
1424  CentralRepoDbUtil.closeResultSet(resultSet);
1425  CentralRepoDbUtil.closeConnection(conn);
1426  }
1427 
1428  return instanceCount;
1429  }
1430 
1431  @Override
1432  public int getFrequencyPercentage(CorrelationAttributeInstance corAttr) throws CentralRepoException, CorrelationAttributeNormalizationException {
1433  if (corAttr == null) {
1434  throw new CentralRepoException("CorrelationAttribute is null");
1435  }
1436  Double uniqueTypeValueTuples = getCountUniqueCaseDataSourceTuplesHavingTypeValue(corAttr.getCorrelationType(), corAttr.getCorrelationValue()).doubleValue();
1437  Double uniqueCaseDataSourceTuples = getCountUniqueDataSources().doubleValue();
1438  Double commonalityPercentage = uniqueTypeValueTuples / uniqueCaseDataSourceTuples * 100;
1439  return commonalityPercentage.intValue();
1440  }
1441 
1452  @Override
1453  public Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
1454  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
1455 
1456  Connection conn = connect();
1457 
1458  Long instanceCount = 0L;
1459  PreparedStatement preparedStatement = null;
1460  ResultSet resultSet = null;
1461 
1462  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
1463  String sql
1464  = "SELECT count(*) FROM (SELECT DISTINCT case_id, data_source_id FROM "
1465  + tableName
1466  + " WHERE value=?) AS "
1467  + tableName
1468  + "_distinct_case_data_source_tuple";
1469 
1470  try {
1471  preparedStatement = conn.prepareStatement(sql);
1472  preparedStatement.setString(1, normalizedValue);
1473  resultSet = preparedStatement.executeQuery();
1474  resultSet.next();
1475  instanceCount = resultSet.getLong(1);
1476  } catch (SQLException ex) {
1477  throw new CentralRepoException("Error counting unique caseDisplayName/dataSource tuples having artifactType and artifactValue.", ex); // NON-NLS
1478  } finally {
1479  CentralRepoDbUtil.closeStatement(preparedStatement);
1480  CentralRepoDbUtil.closeResultSet(resultSet);
1481  CentralRepoDbUtil.closeConnection(conn);
1482  }
1483 
1484  return instanceCount;
1485  }
1486 
1487  @Override
1488  public Long getCountUniqueDataSources() throws CentralRepoException {
1489  Connection conn = connect();
1490 
1491  Long instanceCount = 0L;
1492  PreparedStatement preparedStatement = null;
1493  ResultSet resultSet = null;
1494 
1495  String stmt = "SELECT count(*) FROM data_sources";
1496 
1497  try {
1498  preparedStatement = conn.prepareStatement(stmt);
1499  resultSet = preparedStatement.executeQuery();
1500  resultSet.next();
1501  instanceCount = resultSet.getLong(1);
1502  } catch (SQLException ex) {
1503  throw new CentralRepoException("Error counting data sources.", ex); // NON-NLS
1504  } finally {
1505  CentralRepoDbUtil.closeStatement(preparedStatement);
1506  CentralRepoDbUtil.closeResultSet(resultSet);
1507  CentralRepoDbUtil.closeConnection(conn);
1508  }
1509 
1510  return instanceCount;
1511  }
1512 
1524  @Override
1525  public Long getCountArtifactInstancesByCaseDataSource(CorrelationDataSource correlationDataSource) throws CentralRepoException {
1526  Connection conn = connect();
1527 
1528  Long instanceCount = 0L;
1529  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1530  PreparedStatement preparedStatement = null;
1531  ResultSet resultSet = null;
1532 
1533  //Create query to get count of all instances in the database for the specified case specific data source
1534  String sql = "SELECT 0 ";
1535 
1536  for (CorrelationAttributeInstance.Type type : artifactTypes) {
1537  String table_name = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1538  sql
1539  += "+ (SELECT count(*) FROM "
1540  + table_name
1541  + " WHERE data_source_id=" + correlationDataSource.getID() + ")";
1542  }
1543  try {
1544  preparedStatement = conn.prepareStatement(sql);
1545 
1546  resultSet = preparedStatement.executeQuery();
1547  resultSet.next();
1548  instanceCount = resultSet.getLong(1);
1549  } catch (SQLException ex) {
1550  throw new CentralRepoException("Error counting artifact instances by caseName/dataSource.", ex); // NON-NLS
1551  } finally {
1552  CentralRepoDbUtil.closeStatement(preparedStatement);
1553  CentralRepoDbUtil.closeResultSet(resultSet);
1554  CentralRepoDbUtil.closeConnection(conn);
1555  }
1556 
1557  return instanceCount;
1558  }
1559 
1567  @Override
1568  public void addAttributeInstanceBulk(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1569 
1570  if (eamArtifact.getCorrelationType() == null) {
1571  throw new CentralRepoException("Correlation type is null");
1572  }
1573 
1574  synchronized (bulkArtifacts) {
1575  if (bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())) == null) {
1576  bulkArtifacts.put(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType()), new ArrayList<>());
1577  }
1578  bulkArtifacts.get(CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType())).add(eamArtifact);
1579  bulkArtifactsCount++;
1580 
1581  if (bulkArtifactsCount >= bulkArtifactsThreshold) {
1582  commitAttributeInstancesBulk();
1583  }
1584  }
1585  }
1586 
1592  protected abstract String getConflictClause();
1593 
1598  @Override
1599  public void commitAttributeInstancesBulk() throws CentralRepoException {
1600  List<CorrelationAttributeInstance.Type> artifactTypes = getDefinedCorrelationTypes();
1601 
1602  Connection conn = connect();
1603  PreparedStatement bulkPs = null;
1604 
1605  try {
1606  synchronized (bulkArtifacts) {
1607  if (bulkArtifactsCount == 0) {
1608  return;
1609  }
1610 
1611  for (String tableName : bulkArtifacts.keySet()) {
1612 
1613  String sql
1614  = "INSERT INTO "
1615  + tableName
1616  + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
1617  + "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
1618  + "(SELECT id FROM data_sources WHERE datasource_obj_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
1619  + getConflictClause();
1620 
1621  bulkPs = conn.prepareStatement(sql);
1622 
1623  Collection<CorrelationAttributeInstance> eamArtifacts = bulkArtifacts.get(tableName);
1624  for (CorrelationAttributeInstance eamArtifact : eamArtifacts) {
1625 
1626  if (!eamArtifact.getCorrelationValue().isEmpty()) {
1627 
1628  if (eamArtifact.getCorrelationCase() == null) {
1629  throw new CentralRepoException("CorrelationAttributeInstance case is null for: "
1630  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1631  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1632  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1633  }
1634  if (eamArtifact.getCorrelationDataSource() == null) {
1635  throw new CentralRepoException("CorrelationAttributeInstance data source is null for: "
1636  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1637  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1638  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue());
1639  }
1640  if (eamArtifact.getKnownStatus() == null) {
1641  throw new CentralRepoException("CorrelationAttributeInstance known status is null for: "
1642  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1643  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1644  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue()
1645  + "\n\tEam Instance: "
1646  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1647  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID());
1648  }
1649 
1650  if (eamArtifact.getCorrelationValue().length() < MAX_VALUE_LENGTH) {
1651  bulkPs.setString(1, eamArtifact.getCorrelationCase().getCaseUUID());
1652  bulkPs.setLong(2, eamArtifact.getCorrelationDataSource().getDataSourceObjectID());
1653  bulkPs.setInt(3, eamArtifact.getCorrelationDataSource().getCaseID());
1654  bulkPs.setString(4, eamArtifact.getCorrelationValue());
1655  bulkPs.setString(5, eamArtifact.getFilePath());
1656  bulkPs.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
1657  if ("".equals(eamArtifact.getComment())) {
1658  bulkPs.setNull(7, Types.INTEGER);
1659  } else {
1660  bulkPs.setString(7, eamArtifact.getComment());
1661  }
1662  bulkPs.setLong(8, eamArtifact.getFileObjectId());
1663  bulkPs.addBatch();
1664  } else {
1665  logger.log(Level.WARNING, ("Artifact value too long for central repository."
1666  + "\n\tCorrelationArtifact ID: " + eamArtifact.getID()
1667  + "\n\tCorrelationArtifact Type: " + eamArtifact.getCorrelationType().getDisplayName()
1668  + "\n\tCorrelationArtifact Value: " + eamArtifact.getCorrelationValue())
1669  + "\n\tEam Instance: "
1670  + "\n\t\tCaseId: " + eamArtifact.getCorrelationDataSource().getCaseID()
1671  + "\n\t\tDeviceID: " + eamArtifact.getCorrelationDataSource().getDeviceID()
1672  + "\n\t\tFilePath: " + eamArtifact.getFilePath());
1673  }
1674  }
1675 
1676  }
1677 
1678  bulkPs.executeBatch();
1679  bulkArtifacts.get(tableName).clear();
1680  }
1681 
1682  TimingMetric timingMetric = HealthMonitor.getTimingMetric("Central Repository: Bulk insert");
1683  HealthMonitor.submitTimingMetric(timingMetric);
1684 
1685  // Reset state
1686  bulkArtifactsCount = 0;
1687  }
1688  } catch (SQLException ex) {
1689  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
1690  } finally {
1691  CentralRepoDbUtil.closeStatement(bulkPs);
1692  CentralRepoDbUtil.closeConnection(conn);
1693  }
1694  }
1695 
1699  @Override
1700  public void bulkInsertCases(List<CorrelationCase> cases) throws CentralRepoException {
1701  if (cases == null) {
1702  throw new CentralRepoException("cases argument is null");
1703  }
1704 
1705  if (cases.isEmpty()) {
1706  return;
1707  }
1708 
1709  Connection conn = connect();
1710 
1711  int counter = 0;
1712  PreparedStatement bulkPs = null;
1713  try {
1714  String sql = "INSERT INTO cases(case_uid, org_id, case_name, creation_date, case_number, "
1715  + "examiner_name, examiner_email, examiner_phone, notes) "
1716  + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "
1717  + getConflictClause();
1718  bulkPs = conn.prepareStatement(sql);
1719 
1720  for (CorrelationCase eamCase : cases) {
1721  bulkPs.setString(1, eamCase.getCaseUUID());
1722  if (null == eamCase.getOrg()) {
1723  bulkPs.setNull(2, Types.INTEGER);
1724  } else {
1725  bulkPs.setInt(2, eamCase.getOrg().getOrgID());
1726  }
1727  bulkPs.setString(3, eamCase.getDisplayName());
1728  bulkPs.setString(4, eamCase.getCreationDate());
1729 
1730  if ("".equals(eamCase.getCaseNumber())) {
1731  bulkPs.setNull(5, Types.INTEGER);
1732  } else {
1733  bulkPs.setString(5, eamCase.getCaseNumber());
1734  }
1735  if ("".equals(eamCase.getExaminerName())) {
1736  bulkPs.setNull(6, Types.INTEGER);
1737  } else {
1738  bulkPs.setString(6, eamCase.getExaminerName());
1739  }
1740  if ("".equals(eamCase.getExaminerEmail())) {
1741  bulkPs.setNull(7, Types.INTEGER);
1742  } else {
1743  bulkPs.setString(7, eamCase.getExaminerEmail());
1744  }
1745  if ("".equals(eamCase.getExaminerPhone())) {
1746  bulkPs.setNull(8, Types.INTEGER);
1747  } else {
1748  bulkPs.setString(8, eamCase.getExaminerPhone());
1749  }
1750  if ("".equals(eamCase.getNotes())) {
1751  bulkPs.setNull(9, Types.INTEGER);
1752  } else {
1753  bulkPs.setString(9, eamCase.getNotes());
1754  }
1755 
1756  bulkPs.addBatch();
1757 
1758  counter++;
1759 
1760  // limit a batch's max size to bulkArtifactsThreshold
1761  if (counter >= bulkArtifactsThreshold) {
1762  bulkPs.executeBatch();
1763  counter = 0;
1764  }
1765  }
1766  // send the remaining batch records
1767  bulkPs.executeBatch();
1768  } catch (SQLException ex) {
1769  throw new CentralRepoException("Error inserting bulk cases.", ex); // NON-NLS
1770  } finally {
1771  CentralRepoDbUtil.closeStatement(bulkPs);
1772  CentralRepoDbUtil.closeConnection(conn);
1773  }
1774  }
1775 
1785  @Override
1786  public void updateAttributeInstanceComment(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
1787 
1788  if (eamArtifact == null) {
1789  throw new CentralRepoException("CorrelationAttributeInstance is null");
1790  }
1791  if (eamArtifact.getCorrelationCase() == null) {
1792  throw new CentralRepoException("Correlation case is null");
1793  }
1794  if (eamArtifact.getCorrelationDataSource() == null) {
1795  throw new CentralRepoException("Correlation data source is null");
1796  }
1797  Connection conn = connect();
1798  PreparedStatement preparedQuery = null;
1799  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1800  String sqlUpdate
1801  = "UPDATE "
1802  + tableName
1803  + " SET comment=? "
1804  + "WHERE case_id=? "
1805  + "AND data_source_id=? "
1806  + "AND value=? "
1807  + "AND file_path=?";
1808 
1809  try {
1810  preparedQuery = conn.prepareStatement(sqlUpdate);
1811  preparedQuery.setString(1, eamArtifact.getComment());
1812  preparedQuery.setInt(2, eamArtifact.getCorrelationCase().getID());
1813  preparedQuery.setInt(3, eamArtifact.getCorrelationDataSource().getID());
1814  preparedQuery.setString(4, eamArtifact.getCorrelationValue());
1815  preparedQuery.setString(5, eamArtifact.getFilePath().toLowerCase());
1816  preparedQuery.executeUpdate();
1817  } catch (SQLException ex) {
1818  throw new CentralRepoException("Error getting/setting artifact instance comment=" + eamArtifact.getComment(), ex); // NON-NLS
1819  } finally {
1820  CentralRepoDbUtil.closeStatement(preparedQuery);
1821  CentralRepoDbUtil.closeConnection(conn);
1822  }
1823  }
1824 
1839  @Override
1840  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1841  CorrelationDataSource correlationDataSource, long objectID) throws CentralRepoException, CorrelationAttributeNormalizationException {
1842 
1843  if (correlationCase == null) {
1844  throw new CentralRepoException("Correlation case is null");
1845  }
1846 
1847  Connection conn = connect();
1848 
1849  PreparedStatement preparedStatement = null;
1850  ResultSet resultSet = null;
1851  CorrelationAttributeInstance correlationAttributeInstance = null;
1852 
1853  try {
1854 
1855  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1856  String sql
1857  = "SELECT id, value, file_path, known_status, comment FROM "
1858  + tableName
1859  + " WHERE case_id=?"
1860  + " AND file_obj_id=?";
1861 
1862  preparedStatement = conn.prepareStatement(sql);
1863  preparedStatement.setInt(1, correlationCase.getID());
1864  preparedStatement.setInt(2, (int) objectID);
1865  resultSet = preparedStatement.executeQuery();
1866  if (resultSet.next()) {
1867  int instanceId = resultSet.getInt(1);
1868  String value = resultSet.getString(2);
1869  String filePath = resultSet.getString(3);
1870  int knownStatus = resultSet.getInt(4);
1871  String comment = resultSet.getString(5);
1872 
1873  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1874  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
1875  }
1876  } catch (SQLException ex) {
1877  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1878  } finally {
1879  CentralRepoDbUtil.closeStatement(preparedStatement);
1880  CentralRepoDbUtil.closeResultSet(resultSet);
1881  CentralRepoDbUtil.closeConnection(conn);
1882  }
1883 
1884  return correlationAttributeInstance;
1885  }
1886 
1901  @Override
1902  public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
1903  CorrelationDataSource correlationDataSource, String value, String filePath) throws CentralRepoException, CorrelationAttributeNormalizationException {
1904 
1905  if (correlationCase == null) {
1906  throw new CentralRepoException("Correlation case is null");
1907  }
1908  if (correlationDataSource == null) {
1909  throw new CentralRepoException("Correlation data source is null");
1910  }
1911  if (filePath == null) {
1912  throw new CentralRepoException("Correlation file path is null");
1913  }
1914 
1915  Connection conn = connect();
1916 
1917  PreparedStatement preparedStatement = null;
1918  ResultSet resultSet = null;
1919  CorrelationAttributeInstance correlationAttributeInstance = null;
1920 
1921  try {
1922  String normalizedValue = CorrelationAttributeNormalizer.normalize(type, value);
1923 
1924  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
1925  String sql
1926  = "SELECT id, known_status, comment FROM "
1927  + tableName
1928  + " WHERE case_id=?"
1929  + " AND data_source_id=?"
1930  + " AND value=?"
1931  + " AND file_path=?";
1932 
1933  preparedStatement = conn.prepareStatement(sql);
1934  preparedStatement.setInt(1, correlationCase.getID());
1935  preparedStatement.setInt(2, correlationDataSource.getID());
1936  preparedStatement.setString(3, normalizedValue);
1937  preparedStatement.setString(4, filePath.toLowerCase());
1938  resultSet = preparedStatement.executeQuery();
1939  if (resultSet.next()) {
1940  int instanceId = resultSet.getInt(1);
1941  int knownStatus = resultSet.getInt(2);
1942  String comment = resultSet.getString(3);
1943  //null objectId used because we only fall back to using this method when objectID was not available
1944  correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
1945  instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
1946  }
1947  } catch (SQLException ex) {
1948  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
1949  } finally {
1950  CentralRepoDbUtil.closeStatement(preparedStatement);
1951  CentralRepoDbUtil.closeResultSet(resultSet);
1952  CentralRepoDbUtil.closeConnection(conn);
1953  }
1954 
1955  return correlationAttributeInstance;
1956  }
1957 
1968  @Override
1969  public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws CentralRepoException {
1970  if (eamArtifact == null) {
1971  throw new CentralRepoException("CorrelationAttribute is null");
1972  }
1973  if (knownStatus == null) {
1974  throw new CentralRepoException("Known status is null");
1975  }
1976 
1977  if (eamArtifact.getCorrelationCase() == null) {
1978  throw new CentralRepoException("Correlation case is null");
1979  }
1980  if (eamArtifact.getCorrelationDataSource() == null) {
1981  throw new CentralRepoException("Correlation data source is null");
1982  }
1983 
1984  Connection conn = connect();
1985 
1986  PreparedStatement preparedUpdate = null;
1987  PreparedStatement preparedQuery = null;
1988  ResultSet resultSet = null;
1989 
1990  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
1991 
1992  String sqlQuery
1993  = "SELECT id FROM "
1994  + tableName
1995  + " WHERE case_id=? "
1996  + "AND data_source_id=? "
1997  + "AND value=? "
1998  + "AND file_path=?";
1999 
2000  String sqlUpdate
2001  = "UPDATE "
2002  + tableName
2003  + " SET known_status=? WHERE id=?";
2004 
2005  try {
2006  preparedQuery = conn.prepareStatement(sqlQuery);
2007  preparedQuery.setInt(1, eamArtifact.getCorrelationCase().getID());
2008  preparedQuery.setInt(2, eamArtifact.getCorrelationDataSource().getID());
2009  preparedQuery.setString(3, eamArtifact.getCorrelationValue());
2010  preparedQuery.setString(4, eamArtifact.getFilePath());
2011  resultSet = preparedQuery.executeQuery();
2012  if (resultSet.next()) {
2013  int instance_id = resultSet.getInt("id");
2014  preparedUpdate = conn.prepareStatement(sqlUpdate);
2015 
2016  preparedUpdate.setByte(1, knownStatus.getFileKnownValue());
2017  preparedUpdate.setInt(2, instance_id);
2018 
2019  preparedUpdate.executeUpdate();
2020  } else {
2021  // In this case, the user is tagging something that isn't in the database,
2022  // which means the case and/or datasource may also not be in the database.
2023  // We could improve effiency by keeping a list of all datasources and cases
2024  // in the database, but we don't expect the user to be tagging large numbers
2025  // of items (that didn't have the CE ingest module run on them) at once.
2026  CorrelationCase correlationCaseWithId = getCaseByUUID(eamArtifact.getCorrelationCase().getCaseUUID());
2027  if (null == getDataSource(correlationCaseWithId, eamArtifact.getCorrelationDataSource().getDataSourceObjectID())) {
2028  newDataSource(eamArtifact.getCorrelationDataSource());
2029  }
2030  eamArtifact.setKnownStatus(knownStatus);
2031  addArtifactInstance(eamArtifact);
2032  }
2033 
2034  } catch (SQLException ex) {
2035  throw new CentralRepoException("Error getting/setting artifact instance knownStatus=" + knownStatus.getName(), ex); // NON-NLS
2036  } finally {
2037  CentralRepoDbUtil.closeStatement(preparedUpdate);
2038  CentralRepoDbUtil.closeStatement(preparedQuery);
2039  CentralRepoDbUtil.closeResultSet(resultSet);
2040  CentralRepoDbUtil.closeConnection(conn);
2041  }
2042  }
2043 
2052  @Override
2053  public Long getCountArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2054 
2055  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2056 
2057  Connection conn = connect();
2058 
2059  Long badInstances = 0L;
2060  PreparedStatement preparedStatement = null;
2061  ResultSet resultSet = null;
2062 
2063  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2064  String sql
2065  = "SELECT count(*) FROM "
2066  + tableName
2067  + " WHERE value=? AND known_status=?";
2068 
2069  try {
2070  preparedStatement = conn.prepareStatement(sql);
2071  preparedStatement.setString(1, normalizedValue);
2072  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2073  resultSet = preparedStatement.executeQuery();
2074  resultSet.next();
2075  badInstances = resultSet.getLong(1);
2076  } catch (SQLException ex) {
2077  throw new CentralRepoException("Error getting count of notable artifact instances.", ex); // NON-NLS
2078  } finally {
2079  CentralRepoDbUtil.closeStatement(preparedStatement);
2080  CentralRepoDbUtil.closeResultSet(resultSet);
2081  CentralRepoDbUtil.closeConnection(conn);
2082  }
2083 
2084  return badInstances;
2085  }
2086 
2099  @Override
2100  public List<String> getListCasesHavingArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2101 
2102  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2103 
2104  Connection conn = connect();
2105 
2106  Collection<String> caseNames = new LinkedHashSet<>();
2107 
2108  PreparedStatement preparedStatement = null;
2109  ResultSet resultSet = null;
2110 
2111  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2112  String sql
2113  = "SELECT DISTINCT case_name FROM "
2114  + tableName
2115  + " INNER JOIN cases ON "
2116  + tableName
2117  + ".case_id=cases.id WHERE "
2118  + tableName
2119  + ".value=? AND "
2120  + tableName
2121  + ".known_status=?";
2122 
2123  try {
2124  preparedStatement = conn.prepareStatement(sql);
2125  preparedStatement.setString(1, normalizedValue);
2126  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2127  resultSet = preparedStatement.executeQuery();
2128  while (resultSet.next()) {
2129  caseNames.add(resultSet.getString("case_name"));
2130  }
2131  } catch (SQLException ex) {
2132  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2133  } finally {
2134  CentralRepoDbUtil.closeStatement(preparedStatement);
2135  CentralRepoDbUtil.closeResultSet(resultSet);
2136  CentralRepoDbUtil.closeConnection(conn);
2137  }
2138 
2139  return caseNames.stream().collect(Collectors.toList());
2140  }
2141 
2154  @Override
2155  public List<String> getListCasesHavingArtifactInstances(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2156 
2157  String normalizedValue = CorrelationAttributeNormalizer.normalize(aType, value);
2158 
2159  Connection conn = connect();
2160 
2161  Collection<String> caseNames = new LinkedHashSet<>();
2162 
2163  PreparedStatement preparedStatement = null;
2164  ResultSet resultSet = null;
2165 
2166  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(aType);
2167  String sql
2168  = "SELECT DISTINCT case_name FROM "
2169  + tableName
2170  + " INNER JOIN cases ON "
2171  + tableName
2172  + ".case_id=cases.id WHERE "
2173  + tableName
2174  + ".value=? ";
2175 
2176  try {
2177  preparedStatement = conn.prepareStatement(sql);
2178  preparedStatement.setString(1, normalizedValue);
2179  resultSet = preparedStatement.executeQuery();
2180  while (resultSet.next()) {
2181  caseNames.add(resultSet.getString("case_name"));
2182  }
2183  } catch (SQLException ex) {
2184  throw new CentralRepoException("Error getting notable artifact instances.", ex); // NON-NLS
2185  } finally {
2186  CentralRepoDbUtil.closeStatement(preparedStatement);
2187  CentralRepoDbUtil.closeResultSet(resultSet);
2188  CentralRepoDbUtil.closeConnection(conn);
2189  }
2190 
2191  return caseNames.stream().collect(Collectors.toList());
2192  }
2193 
2201  @Override
2202  public void deleteReferenceSet(int referenceSetID) throws CentralRepoException {
2203  deleteReferenceSetEntries(referenceSetID);
2204  deleteReferenceSetEntry(referenceSetID);
2205  }
2206 
2214  private void deleteReferenceSetEntry(int referenceSetID) throws CentralRepoException {
2215  Connection conn = connect();
2216 
2217  PreparedStatement preparedStatement = null;
2218  String sql = "DELETE FROM reference_sets WHERE id=?";
2219 
2220  try {
2221  preparedStatement = conn.prepareStatement(sql);
2222  preparedStatement.setInt(1, referenceSetID);
2223  preparedStatement.executeUpdate();
2224  } catch (SQLException ex) {
2225  throw new CentralRepoException("Error deleting reference set " + referenceSetID, ex); // NON-NLS
2226  } finally {
2227  CentralRepoDbUtil.closeStatement(preparedStatement);
2228  CentralRepoDbUtil.closeConnection(conn);
2229  }
2230  }
2231 
2240  private void deleteReferenceSetEntries(int referenceSetID) throws CentralRepoException {
2241  Connection conn = connect();
2242 
2243  PreparedStatement preparedStatement = null;
2244  String sql = "DELETE FROM %s WHERE reference_set_id=?";
2245 
2246  // When other reference types are added, this will need to loop over all the tables
2247  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID));
2248 
2249  try {
2250  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2251  preparedStatement.setInt(1, referenceSetID);
2252  preparedStatement.executeUpdate();
2253  } catch (SQLException ex) {
2254  throw new CentralRepoException("Error deleting files from reference set " + referenceSetID, ex); // NON-NLS
2255  } finally {
2256  CentralRepoDbUtil.closeStatement(preparedStatement);
2257  CentralRepoDbUtil.closeConnection(conn);
2258  }
2259  }
2260 
2274  @Override
2275  public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws CentralRepoException {
2276  CentralRepoFileSet refSet = this.getReferenceSetByID(referenceSetID);
2277  if (refSet == null) {
2278  return false;
2279  }
2280 
2281  return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version));
2282  }
2283 
2295  @Override
2296  public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2297  return isValueInReferenceSet(hash, referenceSetID, CorrelationAttributeInstance.FILES_TYPE_ID);
2298  }
2299 
2300  @Override
2301  public HashHitInfo lookupHash(String hash, int referenceSetID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2302  int correlationTypeID = CorrelationAttributeInstance.FILES_TYPE_ID;
2303  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), hash);
2304 
2305  Connection conn = connect();
2306 
2307  PreparedStatement preparedStatement = null;
2308  ResultSet resultSet = null;
2309  String sql = "SELECT value,comment FROM %s WHERE value=? AND reference_set_id=?";
2310 
2311  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2312 
2313  try {
2314  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2315  preparedStatement.setString(1, normalizeValued);
2316  preparedStatement.setInt(2, referenceSetID);
2317  resultSet = preparedStatement.executeQuery();
2318  if (resultSet.next()) {
2319  String comment = resultSet.getString("comment");
2320  String hashFound = resultSet.getString("value");
2321  HashHitInfo found = new HashHitInfo(hashFound, "", "");
2322  found.addComment(comment);
2323  return found;
2324  } else {
2325  return null;
2326  }
2327  } catch (SQLException ex) {
2328  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2329  } finally {
2330  CentralRepoDbUtil.closeStatement(preparedStatement);
2331  CentralRepoDbUtil.closeResultSet(resultSet);
2332  CentralRepoDbUtil.closeConnection(conn);
2333  }
2334  }
2335 
2345  @Override
2346  public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws CentralRepoException, CorrelationAttributeNormalizationException {
2347 
2348  String normalizeValued = CorrelationAttributeNormalizer.normalize(this.getCorrelationTypeById(correlationTypeID), value);
2349 
2350  Connection conn = connect();
2351 
2352  Long matchingInstances = 0L;
2353  PreparedStatement preparedStatement = null;
2354  ResultSet resultSet = null;
2355  String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?";
2356 
2357  String fileTableName = CentralRepoDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID));
2358 
2359  try {
2360  preparedStatement = conn.prepareStatement(String.format(sql, fileTableName));
2361  preparedStatement.setString(1, normalizeValued);
2362  preparedStatement.setInt(2, referenceSetID);
2363  resultSet = preparedStatement.executeQuery();
2364  resultSet.next();
2365  matchingInstances = resultSet.getLong(1);
2366  } catch (SQLException ex) {
2367  throw new CentralRepoException("Error determining if value (" + normalizeValued + ") is in reference set " + referenceSetID, ex); // NON-NLS
2368  } finally {
2369  CentralRepoDbUtil.closeStatement(preparedStatement);
2370  CentralRepoDbUtil.closeResultSet(resultSet);
2371  CentralRepoDbUtil.closeConnection(conn);
2372  }
2373 
2374  return 0 < matchingInstances;
2375  }
2376 
2385  @Override
2386  public boolean isArtifactKnownBadByReference(CorrelationAttributeInstance.Type aType, String value) throws CentralRepoException, CorrelationAttributeNormalizationException {
2387 
2388  //this should be done here so that we can be certain that aType and value are valid before we proceed
2389  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, value);
2390 
2391  // TEMP: Only support file correlation type
2392  if (aType.getId() != CorrelationAttributeInstance.FILES_TYPE_ID) {
2393  return false;
2394  }
2395 
2396  Connection conn = connect();
2397 
2398  Long badInstances = 0L;
2399  PreparedStatement preparedStatement = null;
2400  ResultSet resultSet = null;
2401  String sql = "SELECT count(*) FROM %s WHERE value=? AND known_status=?";
2402 
2403  try {
2404  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
2405  preparedStatement.setString(1, normalizeValued);
2406  preparedStatement.setByte(2, TskData.FileKnown.BAD.getFileKnownValue());
2407  resultSet = preparedStatement.executeQuery();
2408  resultSet.next();
2409  badInstances = resultSet.getLong(1);
2410  } catch (SQLException ex) {
2411  throw new CentralRepoException("Error determining if artifact is notable by reference.", ex); // NON-NLS
2412  } finally {
2413  CentralRepoDbUtil.closeStatement(preparedStatement);
2414  CentralRepoDbUtil.closeResultSet(resultSet);
2415  CentralRepoDbUtil.closeConnection(conn);
2416  }
2417 
2418  return 0 < badInstances;
2419  }
2420 
2429  @Override
2430  public void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2431  if (type == null) {
2432  throw new CentralRepoException("Correlation type is null");
2433  }
2434 
2435  if (instanceTableCallback == null) {
2436  throw new CentralRepoException("Callback interface is null");
2437  }
2438 
2439  Connection conn = connect();
2440  PreparedStatement preparedStatement = null;
2441  ResultSet resultSet = null;
2442  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2443  StringBuilder sql = new StringBuilder();
2444  sql.append("select * from ");
2445  sql.append(tableName);
2446 
2447  try {
2448  preparedStatement = conn.prepareStatement(sql.toString());
2449  resultSet = preparedStatement.executeQuery();
2450  instanceTableCallback.process(resultSet);
2451  } catch (SQLException ex) {
2452  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2453  } finally {
2454  CentralRepoDbUtil.closeStatement(preparedStatement);
2455  CentralRepoDbUtil.closeResultSet(resultSet);
2456  CentralRepoDbUtil.closeConnection(conn);
2457  }
2458  }
2459 
2469  @Override
2470  public void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2471  if (type == null) {
2472  throw new CentralRepoException("Correlation type is null");
2473  }
2474 
2475  if (instanceTableCallback == null) {
2476  throw new CentralRepoException("Callback interface is null");
2477  }
2478 
2479  if (whereClause == null) {
2480  throw new CentralRepoException("Where clause is null");
2481  }
2482 
2483  Connection conn = connect();
2484  PreparedStatement preparedStatement = null;
2485  ResultSet resultSet = null;
2486  String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
2487  StringBuilder sql = new StringBuilder(300);
2488  sql.append("select * from ")
2489  .append(tableName)
2490  .append(" WHERE ")
2491  .append(whereClause);
2492 
2493  try {
2494  preparedStatement = conn.prepareStatement(sql.toString());
2495  resultSet = preparedStatement.executeQuery();
2496  instanceTableCallback.process(resultSet);
2497  } catch (SQLException ex) {
2498  throw new CentralRepoException("Error getting all artifact instances from instances table", ex);
2499  } finally {
2500  CentralRepoDbUtil.closeStatement(preparedStatement);
2501  CentralRepoDbUtil.closeResultSet(resultSet);
2502  CentralRepoDbUtil.closeConnection(conn);
2503  }
2504  }
2505 
2514  @Override
2515  public void processSelectClause(String selectClause, InstanceTableCallback instanceTableCallback) throws CentralRepoException {
2516 
2517  if (instanceTableCallback == null) {
2518  throw new CentralRepoException("Callback interface is null");
2519  }
2520 
2521  if (selectClause == null) {
2522  throw new CentralRepoException("Select clause is null");
2523  }
2524 
2525  Connection conn = connect();
2526  PreparedStatement preparedStatement = null;
2527  ResultSet resultSet = null;
2528  StringBuilder sql = new StringBuilder(300);
2529  sql.append("select ")
2530  .append(selectClause);
2531 
2532  try {
2533  preparedStatement = conn.prepareStatement(sql.toString());
2534  resultSet = preparedStatement.executeQuery();
2535  instanceTableCallback.process(resultSet);
2536  } catch (SQLException ex) {
2537  throw new CentralRepoException("Error running query", ex);
2538  } finally {
2539  CentralRepoDbUtil.closeStatement(preparedStatement);
2540  CentralRepoDbUtil.closeResultSet(resultSet);
2541  CentralRepoDbUtil.closeConnection(conn);
2542  }
2543  }
2544 
2545  @Override
2546  public void executeInsertSQL(String insertClause) throws CentralRepoException {
2547 
2548  if (insertClause == null) {
2549  throw new CentralRepoException("Insert SQL is null");
2550  }
2551 
2552  String sql = getPlatformSpecificInsertSQL(insertClause);
2553  try (Connection conn = connect();
2554  PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
2555  preparedStatement.executeUpdate();
2556  } catch (SQLException ex) {
2557  throw new CentralRepoException(String.format("Error running SQL %s, exception = %s", sql, ex.getMessage()), ex);
2558  }
2559  }
2560 
2561  @Override
2562  public void executeSelectSQL(String selectSQL, CentralRepositoryDbQueryCallback queryCallback) throws CentralRepoException {
2563  if (queryCallback == null) {
2564  throw new CentralRepoException("Query callback is null");
2565  }
2566 
2567  if (selectSQL == null) {
2568  throw new CentralRepoException("Select SQL is null");
2569  }
2570 
2571  StringBuilder sqlSb = new StringBuilder(QUERY_STR_MAX_LEN);
2572  if (selectSQL.trim().toUpperCase().startsWith("SELECT") == false) {
2573  sqlSb.append("SELECT ");
2574  }
2575 
2576  sqlSb.append(selectSQL);
2577 
2578  try (Connection conn = connect();
2579  PreparedStatement preparedStatement = conn.prepareStatement(sqlSb.toString());
2580  ResultSet resultSet = preparedStatement.executeQuery();) {
2581  queryCallback.process(resultSet);
2582  } catch (SQLException ex) {
2583  throw new CentralRepoException(String.format("Error running SQL %s, exception = %s", selectSQL, ex.getMessage()), ex);
2584  }
2585  }
2586 
2587  @Override
2588  public void executeUpdateSQL(String updateSQL) throws CentralRepoException {
2589 
2590  if (updateSQL == null) {
2591  throw new CentralRepoException("Update SQL is null");
2592  }
2593 
2594  StringBuilder sqlSb = new StringBuilder(QUERY_STR_MAX_LEN);
2595  if (updateSQL.trim().toUpperCase().startsWith("UPDATE") == false) {
2596  sqlSb.append("UPDATE ");
2597  }
2598 
2599  sqlSb.append(updateSQL);
2600 
2601  try (Connection conn = connect();
2602  PreparedStatement preparedStatement = conn.prepareStatement(sqlSb.toString());) {
2603  preparedStatement.executeUpdate();
2604  } catch (SQLException ex) {
2605  throw new CentralRepoException(String.format("Error running SQL %s, exception = %s", updateSQL, ex.getMessage()), ex);
2606  }
2607  }
2608 
2609  @Override
2610  public void executeDeleteSQL(String deleteSQL) throws CentralRepoException {
2611 
2612  if (deleteSQL == null) {
2613  throw new CentralRepoException("Delete SQL is null");
2614  }
2615 
2616  StringBuilder sqlSb = new StringBuilder(QUERY_STR_MAX_LEN);
2617  if (deleteSQL.trim().toUpperCase().startsWith("DELETE") == false) {
2618  sqlSb.append("DELETE ");
2619  }
2620 
2621  sqlSb.append(deleteSQL);
2622 
2623  try (Connection conn = connect();
2624  PreparedStatement preparedStatement = conn.prepareStatement(sqlSb.toString());) {
2625  preparedStatement.executeUpdate();
2626  } catch (SQLException ex) {
2627  throw new CentralRepoException(String.format("Error running SQL %s, exception = %s", deleteSQL, ex.getMessage()), ex);
2628  }
2629  }
2630 
2631  @Override
2632  public CentralRepoOrganization newOrganization(CentralRepoOrganization eamOrg) throws CentralRepoException {
2633  if (eamOrg == null) {
2634  throw new CentralRepoException("EamOrganization is null");
2635  } else if (eamOrg.getOrgID() != -1) {
2636  throw new CentralRepoException("EamOrganization already has an ID");
2637  }
2638 
2639  Connection conn = connect();
2640  ResultSet generatedKeys = null;
2641  PreparedStatement preparedStatement = null;
2642  String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?) "
2643  + getConflictClause();
2644 
2645  try {
2646  preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
2647  preparedStatement.setString(1, eamOrg.getName());
2648  preparedStatement.setString(2, eamOrg.getPocName());
2649  preparedStatement.setString(3, eamOrg.getPocEmail());
2650  preparedStatement.setString(4, eamOrg.getPocPhone());
2651 
2652  preparedStatement.executeUpdate();
2653  generatedKeys = preparedStatement.getGeneratedKeys();
2654  if (generatedKeys.next()) {
2655  eamOrg.setOrgID((int) generatedKeys.getLong(1));
2656  return eamOrg;
2657  } else {
2658  throw new SQLException("Creating user failed, no ID obtained.");
2659  }
2660  } catch (SQLException ex) {
2661  throw new CentralRepoException("Error inserting new organization.", ex); // NON-NLS
2662  } finally {
2663  CentralRepoDbUtil.closeStatement(preparedStatement);
2664  CentralRepoDbUtil.closeResultSet(generatedKeys);
2665  CentralRepoDbUtil.closeConnection(conn);
2666  }
2667  }
2668 
2676  @Override
2677  public List<CentralRepoOrganization> getOrganizations() throws CentralRepoException {
2678  Connection conn = connect();
2679 
2680  List<CentralRepoOrganization> orgs = new ArrayList<>();
2681  PreparedStatement preparedStatement = null;
2682  ResultSet resultSet = null;
2683  String sql = "SELECT * FROM organizations";
2684 
2685  try {
2686  preparedStatement = conn.prepareStatement(sql);
2687  resultSet = preparedStatement.executeQuery();
2688  while (resultSet.next()) {
2689  orgs.add(getEamOrganizationFromResultSet(resultSet));
2690  }
2691  return orgs;
2692 
2693  } catch (SQLException ex) {
2694  throw new CentralRepoException("Error getting all organizations.", ex); // NON-NLS
2695  } finally {
2696  CentralRepoDbUtil.closeStatement(preparedStatement);
2697  CentralRepoDbUtil.closeResultSet(resultSet);
2698  CentralRepoDbUtil.closeConnection(conn);
2699  }
2700  }
2701 
2711  @Override
2712  public CentralRepoOrganization getOrganizationByID(int orgID) throws CentralRepoException {
2713  Connection conn = connect();
2714 
2715  PreparedStatement preparedStatement = null;
2716  ResultSet resultSet = null;
2717  String sql = "SELECT * FROM organizations WHERE id=?";
2718 
2719  try {
2720  preparedStatement = conn.prepareStatement(sql);
2721  preparedStatement.setInt(1, orgID);
2722  resultSet = preparedStatement.executeQuery();
2723  resultSet.next();
2724  return getEamOrganizationFromResultSet(resultSet);
2725 
2726  } catch (SQLException ex) {
2727  throw new CentralRepoException("Error getting organization by id.", ex); // NON-NLS
2728  } finally {
2729  CentralRepoDbUtil.closeStatement(preparedStatement);
2730  CentralRepoDbUtil.closeResultSet(resultSet);
2731  CentralRepoDbUtil.closeConnection(conn);
2732  }
2733  }
2734 
2744  @Override
2745  public CentralRepoOrganization getReferenceSetOrganization(int referenceSetID) throws CentralRepoException {
2746 
2747  CentralRepoFileSet globalSet = getReferenceSetByID(referenceSetID);
2748  if (globalSet == null) {
2749  throw new CentralRepoException("Reference set with ID " + referenceSetID + " not found");
2750  }
2751  return (getOrganizationByID(globalSet.getOrgID()));
2752  }
2753 
2761  private void testArgument(CentralRepoOrganization org) throws CentralRepoException {
2762  if (org == null) {
2763  throw new CentralRepoException("EamOrganization is null");
2764  } else if (org.getOrgID() == -1) {
2765  throw new CentralRepoException("Organization has -1 row ID");
2766  }
2767  }
2768 
2780  @Override
2781  public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException {
2782 
2783  String querySQL = "SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "'";
2784  try (Connection connection = connect();
2785  Statement statement = connection.createStatement();
2786  ResultSet resultSet = statement.executeQuery(querySQL);) {
2787 
2788  if (resultSet.next()) {
2789  return new CentralRepoExaminer(resultSet.getLong("id"), resultSet.getString("login_name"));
2790  } else {
2791  // Could not find this user in the Examiner table, add a row for it.
2792  try {
2793  String insertSQL;
2794  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
2795  case POSTGRESQL:
2796  insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')" + getConflictClause(); //NON-NLS
2797  break;
2798  case SQLITE:
2799  insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')"; //NON-NLS
2800  break;
2801  default:
2802  throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS
2803  }
2804  statement.execute(insertSQL);
2805 
2806  // Query the table again to get the row for the user
2807  try (ResultSet resultSet2 = statement.executeQuery(querySQL)) {
2808  if (resultSet2.next()) {
2809  return new CentralRepoExaminer(resultSet2.getLong("id"), resultSet2.getString("login_name"));
2810  } else {
2811  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName);
2812  }
2813  }
2814 
2815  } catch (SQLException ex) {
2816  throw new CentralRepoException("Error inserting row in examiners", ex);
2817  }
2818  }
2819 
2820  } catch (SQLException ex) {
2821  throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex);
2822  }
2823  }
2824 
2833  @Override
2834  public void updateOrganization(CentralRepoOrganization updatedOrganization) throws CentralRepoException {
2835  testArgument(updatedOrganization);
2836 
2837  Connection conn = connect();
2838  PreparedStatement preparedStatement = null;
2839  String sql = "UPDATE organizations SET org_name = ?, poc_name = ?, poc_email = ?, poc_phone = ? WHERE id = ?";
2840  try {
2841  preparedStatement = conn.prepareStatement(sql);
2842  preparedStatement.setString(1, updatedOrganization.getName());
2843  preparedStatement.setString(2, updatedOrganization.getPocName());
2844  preparedStatement.setString(3, updatedOrganization.getPocEmail());
2845  preparedStatement.setString(4, updatedOrganization.getPocPhone());
2846  preparedStatement.setInt(5, updatedOrganization.getOrgID());
2847  preparedStatement.executeUpdate();
2848  } catch (SQLException ex) {
2849  throw new CentralRepoException("Error updating organization.", ex); // NON-NLS
2850  } finally {
2851  CentralRepoDbUtil.closeStatement(preparedStatement);
2852  CentralRepoDbUtil.closeConnection(conn);
2853  }
2854  }
2855 
2856  @Override
2857  public void deleteOrganization(CentralRepoOrganization organizationToDelete) throws CentralRepoException {
2858  testArgument(organizationToDelete);
2859 
2860  Connection conn = connect();
2861  PreparedStatement checkIfUsedStatement = null;
2862  ResultSet resultSet = null;
2863  String checkIfUsedSql = "SELECT (select count(*) FROM cases WHERE org_id=?) + (select count(*) FROM reference_sets WHERE org_id=?)";
2864  PreparedStatement deleteOrgStatement = null;
2865  String deleteOrgSql = "DELETE FROM organizations WHERE id=?";
2866  try {
2867  checkIfUsedStatement = conn.prepareStatement(checkIfUsedSql);
2868  checkIfUsedStatement.setInt(1, organizationToDelete.getOrgID());
2869  checkIfUsedStatement.setInt(2, organizationToDelete.getOrgID());
2870  resultSet = checkIfUsedStatement.executeQuery();
2871  resultSet.next();
2872  if (resultSet.getLong(1) > 0) {
2873  throw new CentralRepoException("Can not delete organization which is currently in use by a case or reference set in the central repository.");
2874  }
2875  deleteOrgStatement = conn.prepareStatement(deleteOrgSql);
2876  deleteOrgStatement.setInt(1, organizationToDelete.getOrgID());
2877  deleteOrgStatement.executeUpdate();
2878  } catch (SQLException ex) {
2879  throw new CentralRepoException("Error executing query when attempting to delete organization by id.", ex); // NON-NLS
2880  } finally {
2881  CentralRepoDbUtil.closeStatement(checkIfUsedStatement);
2882  CentralRepoDbUtil.closeStatement(deleteOrgStatement);
2883  CentralRepoDbUtil.closeResultSet(resultSet);
2884  CentralRepoDbUtil.closeConnection(conn);
2885  }
2886  }
2887 
2897  @Override
2898  public int newReferenceSet(CentralRepoFileSet eamGlobalSet) throws CentralRepoException {
2899  if (eamGlobalSet == null) {
2900  throw new CentralRepoException("EamGlobalSet is null");
2901  }
2902 
2903  if (eamGlobalSet.getFileKnownStatus() == null) {
2904  throw new CentralRepoException("File known status on the EamGlobalSet is null");
2905  }
2906 
2907  if (eamGlobalSet.getType() == null) {
2908  throw new CentralRepoException("Type on the EamGlobalSet is null");
2909  }
2910 
2911  Connection conn = connect();
2912 
2913  PreparedStatement preparedStatement1 = null;
2914  PreparedStatement preparedStatement2 = null;
2915  ResultSet resultSet = null;
2916  String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?) "
2917  + getConflictClause();
2918  String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1";
2919 
2920  try {
2921  preparedStatement1 = conn.prepareStatement(sql1);
2922  preparedStatement1.setInt(1, eamGlobalSet.getOrgID());
2923  preparedStatement1.setString(2, eamGlobalSet.getSetName());
2924  preparedStatement1.setString(3, eamGlobalSet.getVersion());
2925  preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue());
2926  preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly());
2927  preparedStatement1.setInt(6, eamGlobalSet.getType().getId());
2928  preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString());
2929 
2930  preparedStatement1.executeUpdate();
2931 
2932  preparedStatement2 = conn.prepareStatement(sql2);
2933  preparedStatement2.setInt(1, eamGlobalSet.getOrgID());
2934  preparedStatement2.setString(2, eamGlobalSet.getSetName());
2935  preparedStatement2.setString(3, eamGlobalSet.getVersion());
2936  preparedStatement2.setString(4, eamGlobalSet.getImportDate().toString());
2937 
2938  resultSet = preparedStatement2.executeQuery();
2939  resultSet.next();
2940  return resultSet.getInt("id");
2941 
2942  } catch (SQLException ex) {
2943  throw new CentralRepoException("Error inserting new global set.", ex); // NON-NLS
2944  } finally {
2945  CentralRepoDbUtil.closeStatement(preparedStatement1);
2946  CentralRepoDbUtil.closeStatement(preparedStatement2);
2947  CentralRepoDbUtil.closeResultSet(resultSet);
2948  CentralRepoDbUtil.closeConnection(conn);
2949  }
2950  }
2951 
2961  @Override
2962  public CentralRepoFileSet getReferenceSetByID(int referenceSetID) throws CentralRepoException {
2963  Connection conn = connect();
2964 
2965  PreparedStatement preparedStatement1 = null;
2966  ResultSet resultSet = null;
2967  String sql1 = "SELECT * FROM reference_sets WHERE id=?";
2968 
2969  try {
2970  preparedStatement1 = conn.prepareStatement(sql1);
2971  preparedStatement1.setInt(1, referenceSetID);
2972  resultSet = preparedStatement1.executeQuery();
2973  if (resultSet.next()) {
2974  return getEamGlobalSetFromResultSet(resultSet);
2975  } else {
2976  return null;
2977  }
2978 
2979  } catch (SQLException ex) {
2980  throw new CentralRepoException("Error getting reference set by id.", ex); // NON-NLS
2981  } finally {
2982  CentralRepoDbUtil.closeStatement(preparedStatement1);
2983  CentralRepoDbUtil.closeResultSet(resultSet);
2984  CentralRepoDbUtil.closeConnection(conn);
2985  }
2986  }
2987 
2997  @Override
2998  public List<CentralRepoFileSet> getAllReferenceSets(CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
2999 
3000  if (correlationType == null) {
3001  throw new CentralRepoException("Correlation type is null");
3002  }
3003 
3004  List<CentralRepoFileSet> results = new ArrayList<>();
3005  Connection conn = connect();
3006 
3007  PreparedStatement preparedStatement1 = null;
3008  ResultSet resultSet = null;
3009  String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId();
3010 
3011  try {
3012  preparedStatement1 = conn.prepareStatement(sql1);
3013  resultSet = preparedStatement1.executeQuery();
3014  while (resultSet.next()) {
3015  results.add(getEamGlobalSetFromResultSet(resultSet));
3016  }
3017 
3018  } catch (SQLException ex) {
3019  throw new CentralRepoException("Error getting reference sets.", ex); // NON-NLS
3020  } finally {
3021  CentralRepoDbUtil.closeStatement(preparedStatement1);
3022  CentralRepoDbUtil.closeResultSet(resultSet);
3023  CentralRepoDbUtil.closeConnection(conn);
3024  }
3025  return results;
3026  }
3027 
3037  @Override
3038  public void addReferenceInstance(CentralRepoFileInstance eamGlobalFileInstance, CorrelationAttributeInstance.Type correlationType) throws CentralRepoException {
3039  if (eamGlobalFileInstance.getKnownStatus() == null) {
3040  throw new CentralRepoException("Known status of EamGlobalFileInstance is null");
3041  }
3042  if (correlationType == null) {
3043  throw new CentralRepoException("Correlation type is null");
3044  }
3045 
3046  Connection conn = connect();
3047 
3048  PreparedStatement preparedStatement = null;
3049 
3050  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3051  + getConflictClause();
3052 
3053  try {
3054  preparedStatement = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(correlationType)));
3055  preparedStatement.setInt(1, eamGlobalFileInstance.getGlobalSetID());
3056  preparedStatement.setString(2, eamGlobalFileInstance.getMD5Hash());
3057  preparedStatement.setByte(3, eamGlobalFileInstance.getKnownStatus().getFileKnownValue());
3058  preparedStatement.setString(4, eamGlobalFileInstance.getComment());
3059  preparedStatement.executeUpdate();
3060  } catch (SQLException ex) {
3061  throw new CentralRepoException("Error inserting new reference instance into reference_ table.", ex); // NON-NLS
3062  } finally {
3063  CentralRepoDbUtil.closeStatement(preparedStatement);
3064  CentralRepoDbUtil.closeConnection(conn);
3065  }
3066  }
3067 
3080  @Override
3081  public boolean referenceSetExists(String referenceSetName, String version) throws CentralRepoException {
3082  Connection conn = connect();
3083 
3084  PreparedStatement preparedStatement1 = null;
3085  ResultSet resultSet = null;
3086  String sql1 = "SELECT * FROM reference_sets WHERE set_name=? AND version=?";
3087 
3088  try {
3089  preparedStatement1 = conn.prepareStatement(sql1);
3090  preparedStatement1.setString(1, referenceSetName);
3091  preparedStatement1.setString(2, version);
3092  resultSet = preparedStatement1.executeQuery();
3093  return (resultSet.next());
3094 
3095  } catch (SQLException ex) {
3096  throw new CentralRepoException("Error testing whether reference set exists (name: " + referenceSetName
3097  + " version: " + version, ex); // NON-NLS
3098  } finally {
3099  CentralRepoDbUtil.closeStatement(preparedStatement1);
3100  CentralRepoDbUtil.closeResultSet(resultSet);
3101  CentralRepoDbUtil.closeConnection(conn);
3102  }
3103  }
3104 
3110  @Override
3111  public void bulkInsertReferenceTypeEntries(Set<CentralRepoFileInstance> globalInstances, CorrelationAttributeInstance.Type contentType) throws CentralRepoException {
3112  if (contentType == null) {
3113  throw new CentralRepoException("Correlation type is null");
3114  }
3115  if (globalInstances == null) {
3116  throw new CentralRepoException("Null set of EamGlobalFileInstance");
3117  }
3118 
3119  Connection conn = connect();
3120 
3121  PreparedStatement bulkPs = null;
3122  try {
3123  conn.setAutoCommit(false);
3124 
3125  // FUTURE: have a separate global_files table for each Type.
3126  String sql = "INSERT INTO %s(reference_set_id, value, known_status, comment) VALUES (?, ?, ?, ?) "
3127  + getConflictClause();
3128 
3129  bulkPs = conn.prepareStatement(String.format(sql, CentralRepoDbUtil.correlationTypeToReferenceTableName(contentType)));
3130 
3131  for (CentralRepoFileInstance globalInstance : globalInstances) {
3132  if (globalInstance.getKnownStatus() == null) {
3133  throw new CentralRepoException("EamGlobalFileInstance with value " + globalInstance.getMD5Hash() + " has null known status");
3134  }
3135 
3136  bulkPs.setInt(1, globalInstance.getGlobalSetID());
3137  bulkPs.setString(2, globalInstance.getMD5Hash());
3138  bulkPs.setByte(3, globalInstance.getKnownStatus().getFileKnownValue());
3139  bulkPs.setString(4, globalInstance.getComment());
3140  bulkPs.addBatch();
3141  }
3142 
3143  bulkPs.executeBatch();
3144  conn.commit();
3145  } catch (SQLException | CentralRepoException ex) {
3146  try {
3147  conn.rollback();
3148  } catch (SQLException ex2) {
3149  // We're alredy in an error state
3150  }
3151  throw new CentralRepoException("Error inserting bulk artifacts.", ex); // NON-NLS
3152  } finally {
3153  CentralRepoDbUtil.closeStatement(bulkPs);
3154  CentralRepoDbUtil.closeConnection(conn);
3155  }
3156  }
3157 
3168  @Override
3169  public List<CentralRepoFileInstance> getReferenceInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String aValue) throws CentralRepoException, CorrelationAttributeNormalizationException {
3170  String normalizeValued = CorrelationAttributeNormalizer.normalize(aType, aValue);
3171 
3172  Connection conn = connect();
3173 
3174  List<CentralRepoFileInstance> globalFileInstances = new ArrayList<>();
3175  PreparedStatement preparedStatement1 = null;
3176  ResultSet resultSet = null;
3177  String sql1 = "SELECT * FROM %s WHERE value=?";
3178 
3179  try {
3180  preparedStatement1 = conn.prepareStatement(String.format(sql1, CentralRepoDbUtil.correlationTypeToReferenceTableName(aType)));
3181  preparedStatement1.setString(1, normalizeValued);
3182  resultSet = preparedStatement1.executeQuery();
3183  while (resultSet.next()) {
3184  globalFileInstances.add(getEamGlobalFileInstanceFromResultSet(resultSet));
3185  }
3186 
3187  } catch (SQLException ex) {
3188  throw new CentralRepoException("Error getting reference instances by type and value.", ex); // NON-NLS
3189  } finally {
3190  CentralRepoDbUtil.closeStatement(preparedStatement1);
3191  CentralRepoDbUtil.closeResultSet(resultSet);
3192  CentralRepoDbUtil.closeConnection(conn);
3193  }
3194 
3195  return globalFileInstances;
3196  }
3197 
3207  @Override
3208  public int newCorrelationType(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3209  if (newType == null) {
3210  throw new CentralRepoException("Correlation type is null");
3211  }
3212  int typeId;
3213  if (-1 == newType.getId()) {
3214  typeId = newCorrelationTypeNotKnownId(newType);
3215  } else {
3216  typeId = newCorrelationTypeKnownId(newType);
3217  }
3218 
3219  synchronized (typeCache) {
3220  typeCache.put(newType.getId(), newType);
3221  }
3222  return typeId;
3223  }
3224 
3235  public int newCorrelationTypeNotKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3236  Connection conn = connect();
3237 
3238  PreparedStatement preparedStatement = null;
3239  PreparedStatement preparedStatementQuery = null;
3240  ResultSet resultSet = null;
3241  int typeId = 0;
3242  String insertSql;
3243  String querySql;
3244  // if we have a known ID, use it, if not (is -1) let the db assign it.
3245  insertSql = "INSERT INTO correlation_types(display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?) " + getConflictClause();
3246 
3247  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3248 
3249  try {
3250  preparedStatement = conn.prepareStatement(insertSql);
3251 
3252  preparedStatement.setString(1, newType.getDisplayName());
3253  preparedStatement.setString(2, newType.getDbTableName());
3254  preparedStatement.setInt(3, newType.isSupported() ? 1 : 0);
3255  preparedStatement.setInt(4, newType.isEnabled() ? 1 : 0);
3256 
3257  preparedStatement.executeUpdate();
3258 
3259  preparedStatementQuery = conn.prepareStatement(querySql);
3260  preparedStatementQuery.setString(1, newType.getDisplayName());
3261  preparedStatementQuery.setString(2, newType.getDbTableName());
3262 
3263  resultSet = preparedStatementQuery.executeQuery();
3264  if (resultSet.next()) {
3265  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3266  typeId = correlationType.getId();
3267  }
3268  } catch (SQLException ex) {
3269  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3270  } finally {
3271  CentralRepoDbUtil.closeStatement(preparedStatement);
3272  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3273  CentralRepoDbUtil.closeResultSet(resultSet);
3274  CentralRepoDbUtil.closeConnection(conn);
3275  }
3276  return typeId;
3277  }
3278 
3288  private int newCorrelationTypeKnownId(CorrelationAttributeInstance.Type newType) throws CentralRepoException {
3289  Connection conn = connect();
3290 
3291  PreparedStatement preparedStatement = null;
3292  PreparedStatement preparedStatementQuery = null;
3293  ResultSet resultSet = null;
3294  int typeId = 0;
3295  String insertSql;
3296  String querySql;
3297  // if we have a known ID, use it, if not (is -1) let the db assign it.
3298  insertSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
3299 
3300  querySql = "SELECT * FROM correlation_types WHERE display_name=? AND db_table_name=?";
3301 
3302  try {
3303  preparedStatement = conn.prepareStatement(insertSql);
3304 
3305  preparedStatement.setInt(1, newType.getId());
3306  preparedStatement.setString(2, newType.getDisplayName());
3307  preparedStatement.setString(3, newType.getDbTableName());
3308  preparedStatement.setInt(4, newType.isSupported() ? 1 : 0);
3309  preparedStatement.setInt(5, newType.isEnabled() ? 1 : 0);
3310 
3311  preparedStatement.executeUpdate();
3312 
3313  preparedStatementQuery = conn.prepareStatement(querySql);
3314  preparedStatementQuery.setString(1, newType.getDisplayName());
3315  preparedStatementQuery.setString(2, newType.getDbTableName());
3316 
3317  resultSet = preparedStatementQuery.executeQuery();
3318  if (resultSet.next()) {
3319  CorrelationAttributeInstance.Type correlationType = getCorrelationTypeFromResultSet(resultSet);
3320  typeId = correlationType.getId();
3321  }
3322  } catch (SQLException ex) {
3323  throw new CentralRepoException("Error inserting new correlation type.", ex); // NON-NLS
3324  } finally {
3325  CentralRepoDbUtil.closeStatement(preparedStatement);
3326  CentralRepoDbUtil.closeStatement(preparedStatementQuery);
3327  CentralRepoDbUtil.closeResultSet(resultSet);
3328  CentralRepoDbUtil.closeConnection(conn);
3329  }
3330  return typeId;
3331  }
3332 
3333  @Override
3334  public List<CorrelationAttributeInstance.Type> getDefinedCorrelationTypes() throws CentralRepoException {
3335 
3336  synchronized (typeCache) {
3337  if (isCRTypeCacheInitialized == false) {
3338  getCorrelationTypesFromCr();
3339  }
3340  return new ArrayList<>(typeCache.asMap().values());
3341  }
3342  }
3343 
3353  @Override
3354  public List<CorrelationAttributeInstance.Type> getEnabledCorrelationTypes() throws CentralRepoException {
3355  Connection conn = connect();
3356 
3357  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3358  PreparedStatement preparedStatement = null;
3359  ResultSet resultSet = null;
3360  String sql = "SELECT * FROM correlation_types WHERE enabled=1";
3361 
3362  try {
3363  preparedStatement = conn.prepareStatement(sql);
3364  resultSet = preparedStatement.executeQuery();
3365  while (resultSet.next()) {
3366  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3367  }
3368  return aTypes;
3369 
3370  } catch (SQLException ex) {
3371  throw new CentralRepoException("Error getting enabled correlation types.", ex); // NON-NLS
3372  } finally {
3373  CentralRepoDbUtil.closeStatement(preparedStatement);
3374  CentralRepoDbUtil.closeResultSet(resultSet);
3375  CentralRepoDbUtil.closeConnection(conn);
3376  }
3377  }
3378 
3388  @Override
3389  public List<CorrelationAttributeInstance.Type> getSupportedCorrelationTypes() throws CentralRepoException {
3390  Connection conn = connect();
3391 
3392  List<CorrelationAttributeInstance.Type> aTypes = new ArrayList<>();
3393  PreparedStatement preparedStatement = null;
3394  ResultSet resultSet = null;
3395  String sql = "SELECT * FROM correlation_types WHERE supported=1";
3396 
3397  try {
3398  preparedStatement = conn.prepareStatement(sql);
3399  resultSet = preparedStatement.executeQuery();
3400  while (resultSet.next()) {
3401  aTypes.add(getCorrelationTypeFromResultSet(resultSet));
3402  }
3403  return aTypes;
3404 
3405  } catch (SQLException ex) {
3406  throw new CentralRepoException("Error getting supported correlation types.", ex); // NON-NLS
3407  } finally {
3408  CentralRepoDbUtil.closeStatement(preparedStatement);
3409  CentralRepoDbUtil.closeResultSet(resultSet);
3410  CentralRepoDbUtil.closeConnection(conn);
3411  }
3412  }
3413 
3421  @Override
3422  public void updateCorrelationType(CorrelationAttributeInstance.Type aType) throws CentralRepoException {
3423  Connection conn = connect();
3424 
3425  PreparedStatement preparedStatement = null;
3426  String sql = "UPDATE correlation_types SET display_name=?, db_table_name=?, supported=?, enabled=? WHERE id=?";
3427 
3428  try {
3429  preparedStatement = conn.prepareStatement(sql);
3430  preparedStatement.setString(1, aType.getDisplayName());
3431  preparedStatement.setString(2, aType.getDbTableName());
3432  preparedStatement.setInt(3, aType.isSupported() ? 1 : 0);
3433  preparedStatement.setInt(4, aType.isEnabled() ? 1 : 0);
3434  preparedStatement.setInt(5, aType.getId());
3435  preparedStatement.executeUpdate();
3436  synchronized (typeCache) {
3437  typeCache.put(aType.getId(), aType);
3438  }
3439  } catch (SQLException ex) {
3440  throw new CentralRepoException("Error updating correlation type.", ex); // NON-NLS
3441  } finally {
3442  CentralRepoDbUtil.closeStatement(preparedStatement);
3443  CentralRepoDbUtil.closeConnection(conn);
3444  }
3445 
3446  }
3447 
3457  @Override
3458  public CorrelationAttributeInstance.Type getCorrelationTypeById(int typeId) throws CentralRepoException {
3459  try {
3460  synchronized (typeCache) {
3461  return typeCache.get(typeId, () -> getCorrelationTypeByIdFromCr(typeId));
3462  }
3463  } catch (CacheLoader.InvalidCacheLoadException ignored) {
3464  //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
3465  return null;
3466  } catch (ExecutionException ex) {
3467  throw new CentralRepoException("Error getting correlation type", ex);
3468  }
3469  }
3470 
3480  private CorrelationAttributeInstance.Type getCorrelationTypeByIdFromCr(int typeId) throws CentralRepoException {
3481  Connection conn = connect();
3482 
3483  CorrelationAttributeInstance.Type aType;
3484  PreparedStatement preparedStatement = null;
3485  ResultSet resultSet = null;
3486  String sql = "SELECT * FROM correlation_types WHERE id=?";
3487 
3488  try {
3489  preparedStatement = conn.prepareStatement(sql);
3490  preparedStatement.setInt(1, typeId);
3491  resultSet = preparedStatement.executeQuery();
3492  if (resultSet.next()) {
3493  aType = getCorrelationTypeFromResultSet(resultSet);
3494  return aType;
3495  } else {
3496  throw new CentralRepoException("Failed to find entry for correlation type ID = " + typeId);
3497  }
3498 
3499  } catch (SQLException ex) {
3500  throw new CentralRepoException("Error getting correlation type by id.", ex); // NON-NLS
3501  } finally {
3502  CentralRepoDbUtil.closeStatement(preparedStatement);
3503  CentralRepoDbUtil.closeResultSet(resultSet);
3504  CentralRepoDbUtil.closeConnection(conn);
3505  }
3506  }
3507 
3514  private void getCorrelationTypesFromCr() throws CentralRepoException {
3515 
3516  // clear out the cache
3517  synchronized (typeCache) {
3518  typeCache.invalidateAll();
3519  isCRTypeCacheInitialized = false;
3520  }
3521 
3522  String sql = "SELECT * FROM correlation_types";
3523  try (Connection conn = connect();
3524  PreparedStatement preparedStatement = conn.prepareStatement(sql);
3525  ResultSet resultSet = preparedStatement.executeQuery();) {
3526 
3527  synchronized (typeCache) {
3528  while (resultSet.next()) {
3529  CorrelationAttributeInstance.Type aType = getCorrelationTypeFromResultSet(resultSet);
3530  typeCache.put(aType.getId(), aType);
3531  }
3532  isCRTypeCacheInitialized = true;
3533  }
3534  } catch (SQLException ex) {
3535  throw new CentralRepoException("Error getting correlation types.", ex); // NON-NLS
3536  }
3537  }
3538 
3549  private CorrelationCase getEamCaseFromResultSet(ResultSet resultSet) throws SQLException {
3550  if (null == resultSet) {
3551  return null;
3552  }
3553 
3554  CentralRepoOrganization eamOrg = null;
3555 
3556  resultSet.getInt("org_id");
3557  if (!resultSet.wasNull()) {
3558 
3559  eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3560  resultSet.getString("org_name"),
3561  resultSet.getString("poc_name"),
3562  resultSet.getString("poc_email"),
3563  resultSet.getString("poc_phone"));
3564  }
3565 
3566  CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3567  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3568  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
3569 
3570  return eamCase;
3571  }
3572 
3573  private CorrelationDataSource getEamDataSourceFromResultSet(ResultSet resultSet) throws SQLException {
3574  if (null == resultSet) {
3575  return null;
3576  }
3577 
3578  CorrelationDataSource eamDataSource = new CorrelationDataSource(
3579  resultSet.getInt("case_id"),
3580  resultSet.getInt("id"),
3581  resultSet.getString("device_id"),
3582  resultSet.getString("name"),
3583  resultSet.getLong("datasource_obj_id"),
3584  resultSet.getString("md5"),
3585  resultSet.getString("sha1"),
3586  resultSet.getString("sha256")
3587  );
3588 
3589  return eamDataSource;
3590  }
3591 
3592  private CorrelationAttributeInstance.Type getCorrelationTypeFromResultSet(ResultSet resultSet) throws CentralRepoException, SQLException {
3593  if (null == resultSet) {
3594  return null;
3595  }
3596 
3597  CorrelationAttributeInstance.Type eamArtifactType = new CorrelationAttributeInstance.Type(
3598  resultSet.getInt("id"),
3599  resultSet.getString("display_name"),
3600  resultSet.getString("db_table_name"),
3601  resultSet.getBoolean("supported"),
3602  resultSet.getBoolean("enabled")
3603  );
3604 
3605  return eamArtifactType;
3606  }
3607 
3618  private CorrelationAttributeInstance getEamArtifactInstanceFromResultSet(ResultSet resultSet, CorrelationAttributeInstance.Type aType) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3619  if (null == resultSet) {
3620  return null;
3621  }
3622 
3623  CentralRepoOrganization eamOrg = new CentralRepoOrganization(resultSet.getInt("org_id"),
3624  resultSet.getString("org_name"),
3625  resultSet.getString("poc_name"),
3626  resultSet.getString("poc_email"),
3627  resultSet.getString("poc_phone"));
3628 
3629  return new CorrelationAttributeInstance(
3630  aType,
3631  resultSet.getString("value"),
3632  resultSet.getInt("instance_id"),
3633  new CorrelationCase(resultSet.getInt("id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
3634  resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
3635  resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes")),
3636  new CorrelationDataSource(
3637  resultSet.getInt("id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name"),
3638  resultSet.getLong("datasource_obj_id"), resultSet.getString("md5"), resultSet.getString("sha1"), resultSet.getString("sha256")),
3639  resultSet.getString("file_path"),
3640  resultSet.getString("comment"),
3641  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3642  resultSet.getLong("file_obj_id"));
3643  }
3644 
3645  private CentralRepoOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
3646  if (null == resultSet) {
3647  return null;
3648  }
3649 
3650  return new CentralRepoOrganization(
3651  resultSet.getInt("id"),
3652  resultSet.getString("org_name"),
3653  resultSet.getString("poc_name"),
3654  resultSet.getString("poc_email"),
3655  resultSet.getString("poc_phone")
3656  );
3657  }
3658 
3659  private CentralRepoFileSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException {
3660  if (null == resultSet) {
3661  return null;
3662  }
3663 
3664  return new CentralRepoFileSet(
3665  resultSet.getInt("id"),
3666  resultSet.getInt("org_id"),
3667  resultSet.getString("set_name"),
3668  resultSet.getString("version"),
3669  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3670  resultSet.getBoolean("read_only"),
3671  CentralRepository.getInstance().getCorrelationTypeById(resultSet.getInt("type")),
3672  LocalDate.parse(resultSet.getString("import_date"))
3673  );
3674  }
3675 
3676  private CentralRepoFileInstance getEamGlobalFileInstanceFromResultSet(ResultSet resultSet) throws SQLException, CentralRepoException, CorrelationAttributeNormalizationException {
3677  if (null == resultSet) {
3678  return null;
3679  }
3680 
3681  return new CentralRepoFileInstance(
3682  resultSet.getInt("id"),
3683  resultSet.getInt("reference_set_id"),
3684  resultSet.getString("value"),
3685  TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
3686  resultSet.getString("comment")
3687  );
3688  }
3689 
3690  private String getPlatformSpecificInsertSQL(String sql) throws CentralRepoException {
3691 
3692  switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) {
3693  case POSTGRESQL:
3694  return "INSERT " + sql + " ON CONFLICT DO NOTHING"; //NON-NLS
3695  case SQLITE:
3696  return "INSERT OR IGNORE " + sql;
3697 
3698  default:
3699  throw new CentralRepoException("Unknown Central Repo DB platform" + CentralRepoDbManager.getSavedDbChoice().getDbPlatform());
3700  }
3701  }
3702 
3713  abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
3714 
3720  @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.",
3721  "# {0} - minorVersion",
3722  "AbstractSqlEamDb.badMinorSchema.message=Bad value for schema minor version ({0}) - database is corrupt.",
3723  "AbstractSqlEamDb.failedToReadMinorVersion.message=Failed to read schema minor version for Central Repository.",
3724  "# {0} - majorVersion",
3725  "AbstractSqlEamDb.badMajorSchema.message=Bad value for schema version ({0}) - database is corrupt.",
3726  "AbstractSqlEamDb.failedToReadMajorVersion.message=Failed to read schema version for Central Repository.",
3727  "# {0} - platformName",
3728  "AbstractSqlEamDb.cannotUpgrage.message=Currently selected database platform \"{0}\" can not be upgraded."})
3729  @Override
3730  public void upgradeSchema() throws CentralRepoException, SQLException, IncompatibleCentralRepoException {
3731 
3732  ResultSet resultSet = null;
3733  Statement statement = null;
3734  PreparedStatement preparedStatement = null;
3735  Connection conn = null;
3736  CentralRepoPlatforms selectedPlatform = null;
3737  try {
3738 
3739  conn = connect(false);
3740  conn.setAutoCommit(false);
3741  statement = conn.createStatement();
3742  selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
3743  int minorVersion = 0;
3744  String minorVersionStr = null;
3745  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
3746  if (resultSet.next()) {
3747  minorVersionStr = resultSet.getString("value");
3748  try {
3749  minorVersion = Integer.parseInt(minorVersionStr);
3750  } catch (NumberFormatException ex) {
3751  throw new CentralRepoException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMinorSchema_message(minorVersionStr), ex);
3752  }
3753  } else {
3754  throw new CentralRepoException("Failed to read schema minor version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMinorVersion_message());
3755  }
3756 
3757  int majorVersion = 0;
3758  String majorVersionStr = null;
3759  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "'");
3760  if (resultSet.next()) {
3761  majorVersionStr = resultSet.getString("value");
3762  try {
3763  majorVersion = Integer.parseInt(majorVersionStr);
3764  } catch (NumberFormatException ex) {
3765  throw new CentralRepoException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt", Bundle.AbstractSqlEamDb_badMajorSchema_message(majorVersionStr), ex);
3766  }
3767  } else {
3768  throw new CentralRepoException("Failed to read schema major version from db_info table", Bundle.AbstractSqlEamDb_failedToReadMajorVersion_message());
3769  }
3770 
3771  /*
3772  * IMPORTANT: The code that follows had a bug in it prior to Autopsy
3773  * 4.10.0. The consequence of the bug is that the schema version
3774  * number is always reset to 1.0 or 1.1 if a Central Repository is
3775  * opened by an Autopsy 4.9.1 or earlier client. To cope with this,
3776  * there is an effort in updates to 1.2 and greater to not retry
3777  * schema updates that may already have been done once.
3778  */
3779  CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
3780 
3781  //compare the major versions for compatability
3782  //we can not use the CaseDbSchemaVersionNumber.isCompatible method
3783  //because it is specific to case db schema versions only supporting major versions greater than 1
3784  if (SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() < dbSchemaVersion.getMajor()) {
3785  throw new IncompatibleCentralRepoException(Bundle.AbstractSqlEamDb_upgradeSchema_incompatible());
3786  }
3787  if (dbSchemaVersion.equals(SOFTWARE_CR_DB_SCHEMA_VERSION)) {
3788  logger.log(Level.INFO, "Central Repository is up to date");
3789  return;
3790  }
3791  if (dbSchemaVersion.compareTo(SOFTWARE_CR_DB_SCHEMA_VERSION) > 0) {
3792  logger.log(Level.INFO, "Central Repository is of newer version than software creates");
3793  return;
3794  }
3795 
3796  /*
3797  * Update to 1.1
3798  */
3799  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
3800  statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
3801  statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
3802  statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
3803 
3804  // There's an outide chance that the user has already made an organization with the default name,
3805  // and the default org being missing will not impact any database operations, so continue on
3806  // regardless of whether this succeeds.
3807  CentralRepoDbUtil.insertDefaultOrganization(conn);
3808  }
3809 
3810  /*
3811  * Update to 1.2
3812  */
3813  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
3814  final String addIntegerColumnTemplate = "ALTER TABLE %s ADD COLUMN %s INTEGER;"; //NON-NLS
3815 
3816  final String addSsidTableTemplate = RdbmsCentralRepoFactory.getCreateArtifactInstancesTableTemplate(selectedPlatform);
3817  final String addCaseIdIndexTemplate = RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate();
3818  final String addDataSourceIdIndexTemplate = RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate();
3819  final String addValueIndexTemplate = RdbmsCentralRepoFactory.getAddValueIndexTemplate();
3820  final String addKnownStatusIndexTemplate = RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate();
3821  final String addObjectIdIndexTemplate = RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate();
3822 
3823  final String addAttributeSql;
3824  //get the data base specific code for creating a new _instance table
3825  switch (selectedPlatform) {
3826  case POSTGRESQL:
3827  addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
3828  break;
3829  case SQLITE:
3830  addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
3831  break;
3832  default:
3833  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3834  }
3835 
3836  final String dataSourcesTableName = "data_sources";
3837  final String dataSourceObjectIdColumnName = "datasource_obj_id";
3838  if (!doesColumnExist(conn, dataSourcesTableName, dataSourceObjectIdColumnName)) {
3839  statement.execute(String.format(addIntegerColumnTemplate, dataSourcesTableName, dataSourceObjectIdColumnName)); //NON-NLS
3840  }
3841  final String dataSourceObjectIdIndexTemplate = "CREATE INDEX IF NOT EXISTS datasource_object_id ON data_sources (%s)";
3842  statement.execute(String.format(dataSourceObjectIdIndexTemplate, dataSourceObjectIdColumnName));
3843  List<String> instaceTablesToAdd = new ArrayList<>();
3844  //update central repository to be able to store new correlation attributes
3845  final String wirelessNetworksDbTableName = "wireless_networks";
3846  instaceTablesToAdd.add(wirelessNetworksDbTableName + "_instances");
3847  final String macAddressDbTableName = "mac_address";
3848  instaceTablesToAdd.add(macAddressDbTableName + "_instances");
3849  final String imeiNumberDbTableName = "imei_number";
3850  instaceTablesToAdd.add(imeiNumberDbTableName + "_instances");
3851  final String iccidNumberDbTableName = "iccid_number";
3852  instaceTablesToAdd.add(iccidNumberDbTableName + "_instances");
3853  final String imsiNumberDbTableName = "imsi_number";
3854  instaceTablesToAdd.add(imsiNumberDbTableName + "_instances");
3855 
3856  //add the wireless_networks attribute to the correlation_types table
3857  preparedStatement = conn.prepareStatement(addAttributeSql);
3858  preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
3859  preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
3860  preparedStatement.setString(3, wirelessNetworksDbTableName);
3861  preparedStatement.setInt(4, 1);
3862  preparedStatement.setInt(5, 1);
3863  preparedStatement.execute();
3864 
3865  //add the mac_address attribute to the correlation_types table
3866  preparedStatement = conn.prepareStatement(addAttributeSql);
3867  preparedStatement.setInt(1, CorrelationAttributeInstance.MAC_TYPE_ID);
3868  preparedStatement.setString(2, Bundle.CorrelationType_MAC_displayName());
3869  preparedStatement.setString(3, macAddressDbTableName);
3870  preparedStatement.setInt(4, 1);
3871  preparedStatement.setInt(5, 1);
3872  preparedStatement.execute();
3873 
3874  //add the imei_number attribute to the correlation_types table
3875  preparedStatement = conn.prepareStatement(addAttributeSql);
3876  preparedStatement.setInt(1, CorrelationAttributeInstance.IMEI_TYPE_ID);
3877  preparedStatement.setString(2, Bundle.CorrelationType_IMEI_displayName());
3878  preparedStatement.setString(3, imeiNumberDbTableName);
3879  preparedStatement.setInt(4, 1);
3880  preparedStatement.setInt(5, 1);
3881  preparedStatement.execute();
3882 
3883  //add the imsi_number attribute to the correlation_types table
3884  preparedStatement = conn.prepareStatement(addAttributeSql);
3885  preparedStatement.setInt(1, CorrelationAttributeInstance.IMSI_TYPE_ID);
3886  preparedStatement.setString(2, Bundle.CorrelationType_IMSI_displayName());
3887  preparedStatement.setString(3, imsiNumberDbTableName);
3888  preparedStatement.setInt(4, 1);
3889  preparedStatement.setInt(5, 1);
3890  preparedStatement.execute();
3891 
3892  //add the iccid_number attribute to the correlation_types table
3893  preparedStatement = conn.prepareStatement(addAttributeSql);
3894  preparedStatement.setInt(1, CorrelationAttributeInstance.ICCID_TYPE_ID);
3895  preparedStatement.setString(2, Bundle.CorrelationType_ICCID_displayName());
3896  preparedStatement.setString(3, iccidNumberDbTableName);
3897  preparedStatement.setInt(4, 1);
3898  preparedStatement.setInt(5, 1);
3899  preparedStatement.execute();
3900 
3901  //create a new _instances tables and add indexes for their columns
3902  for (String tableName : instaceTablesToAdd) {
3903  statement.execute(String.format(addSsidTableTemplate, tableName, tableName));
3904  statement.execute(String.format(addCaseIdIndexTemplate, tableName, tableName));
3905  statement.execute(String.format(addDataSourceIdIndexTemplate, tableName, tableName));
3906  statement.execute(String.format(addValueIndexTemplate, tableName, tableName));
3907  statement.execute(String.format(addKnownStatusIndexTemplate, tableName, tableName));
3908  }
3909 
3910  //add file_obj_id column to _instances table which do not already have it
3911  String instance_type_dbname;
3912  final String objectIdColumnName = "file_obj_id";
3913  for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
3914  instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
3915  if (!doesColumnExist(conn, instance_type_dbname, objectIdColumnName)) {
3916  statement.execute(String.format(addIntegerColumnTemplate, instance_type_dbname, objectIdColumnName)); //NON-NLS
3917  }
3918  statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
3919  }
3920 
3921  /*
3922  * Add hash columns to the data_sources table.
3923  */
3924  if (!doesColumnExist(conn, dataSourcesTableName, "md5")) {
3925  statement.execute("ALTER TABLE data_sources ADD COLUMN md5 TEXT DEFAULT NULL");
3926  }
3927  if (!doesColumnExist(conn, dataSourcesTableName, "sha1")) {
3928  statement.execute("ALTER TABLE data_sources ADD COLUMN sha1 TEXT DEFAULT NULL");
3929  }
3930  if (!doesColumnExist(conn, dataSourcesTableName, "sha256")) {
3931  statement.execute("ALTER TABLE data_sources ADD COLUMN sha256 TEXT DEFAULT NULL");
3932  }
3933 
3934  /*
3935  * Drop the db_info table and add it back in with the name
3936  * column having a UNIQUE constraint. The name column could now
3937  * be used as the primary key, but the essentially useless id
3938  * column is retained for the sake of backwards compatibility.
3939  * Note that the creation schema version number is set to 0.0 to
3940  * indicate that it is unknown.
3941  */
3942  String creationMajorVer;
3943  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "'");
3944  if (resultSet.next()) {
3945  creationMajorVer = resultSet.getString("value");
3946  } else {
3947  creationMajorVer = "0";
3948  }
3949  String creationMinorVer;
3950  resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name = '" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "'");
3951  if (resultSet.next()) {
3952  creationMinorVer = resultSet.getString("value");
3953  } else {
3954  creationMinorVer = "0";
3955  }
3956  statement.execute("DROP TABLE db_info");
3957  if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
3958  statement.execute("CREATE TABLE db_info (id SERIAL, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3959  } else {
3960  statement.execute("CREATE TABLE db_info (id INTEGER PRIMARY KEY, name TEXT UNIQUE NOT NULL, value TEXT NOT NULL)");
3961  }
3962  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MAJOR_VERSION_KEY + "','" + majorVersionStr + "')");
3963  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "','" + minorVersionStr + "')");
3964  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "','" + creationMajorVer + "')");
3965  statement.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "','" + creationMinorVer + "')");
3966  }
3967  /*
3968  * Update to 1.3
3969  */
3970  if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 3)) < 0) {
3971  switch (selectedPlatform) {
3972  case POSTGRESQL:
3973  statement.execute("ALTER TABLE data_sources DROP CONSTRAINT datasource_unique");
3974  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3975  statement.execute("ALTER TABLE data_sources ADD CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id)");
3976 
3977  break;
3978  case SQLITE:
3979  statement.execute("DROP INDEX IF EXISTS data_sources_name");
3980  statement.execute("DROP INDEX IF EXISTS data_sources_object_id");
3981  statement.execute("ALTER TABLE data_sources RENAME TO old_data_sources");
3982  //unique constraint for upgraded data_sources table is purposefully different than new data_sources table
3983  statement.execute("CREATE TABLE IF NOT EXISTS data_sources (id integer primary key autoincrement NOT NULL,"
3984  + "case_id integer NOT NULL,device_id text NOT NULL,name text NOT NULL,datasource_obj_id integer,"
3985  + "md5 text DEFAULT NULL,sha1 text DEFAULT NULL,sha256 text DEFAULT NULL,"
3986  + "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
3987  + "CONSTRAINT datasource_unique UNIQUE (case_id, device_id, name, datasource_obj_id))");
3988  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesNameIndexStatement());
3989  statement.execute(RdbmsCentralRepoFactory.getAddDataSourcesObjectIdIndexStatement());
3990  statement.execute("INSERT INTO data_sources SELECT * FROM old_data_sources");
3991  statement.execute("DROP TABLE old_data_sources");
3992  break;
3993  default:
3994  throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
3995  }
3996  }
3997 
3998  // Upgrade to 1.4
3999  (new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
4000 
4001  // Upgrade to 1.5
4002  (new CentralRepoDbUpgrader14To15()).upgradeSchema(dbSchemaVersion, conn);
4003 
4004  updateSchemaVersion(conn);
4005  conn.commit();
4006  logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
4007  } catch (SQLException | CentralRepoException ex) {
4008  try {
4009  if (conn != null) {
4010  conn.rollback();
4011  }
4012  } catch (SQLException ex2) {
4013  logger.log(Level.SEVERE, String.format("Central Repository rollback of failed schema update to %s failed", SOFTWARE_CR_DB_SCHEMA_VERSION), ex2);
4014  }
4015  throw ex;
4016  } finally {
4017  CentralRepoDbUtil.closeResultSet(resultSet);
4018  CentralRepoDbUtil.closeStatement(preparedStatement);
4019  CentralRepoDbUtil.closeStatement(statement);
4020  CentralRepoDbUtil.closeConnection(conn);
4021  }
4022  }
4023 
4024 }
CentralRepoAccount getOrCreateAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)

Copyright © 2012-2020 Basis Technology. Generated on: Mon Jul 6 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.