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

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.