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

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